fs_mgr_verity.c revision e32b8952a630f6a125f2a151f3084b59b9074bb8
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <inttypes.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <string.h> 21#include <unistd.h> 22#include <fcntl.h> 23#include <ctype.h> 24#include <sys/mount.h> 25#include <sys/stat.h> 26#include <errno.h> 27#include <sys/types.h> 28#include <sys/wait.h> 29#include <libgen.h> 30#include <time.h> 31 32#include <private/android_filesystem_config.h> 33#include <logwrap/logwrap.h> 34 35#include "mincrypt/rsa.h" 36#include "mincrypt/sha.h" 37#include "mincrypt/sha256.h" 38 39#include "ext4_sb.h" 40 41#include "fs_mgr_priv.h" 42#include "fs_mgr_priv_verity.h" 43 44#define VERITY_METADATA_SIZE 32768 45#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001 46#define VERITY_TABLE_RSA_KEY "/verity_key" 47 48extern struct fs_info info; 49 50static RSAPublicKey *load_key(char *path) 51{ 52 FILE *f; 53 RSAPublicKey *key; 54 55 key = malloc(sizeof(RSAPublicKey)); 56 if (!key) { 57 ERROR("Can't malloc key\n"); 58 return NULL; 59 } 60 61 f = fopen(path, "r"); 62 if (!f) { 63 ERROR("Can't open '%s'\n", path); 64 free(key); 65 return NULL; 66 } 67 68 if (!fread(key, sizeof(*key), 1, f)) { 69 ERROR("Could not read key!"); 70 fclose(f); 71 free(key); 72 return NULL; 73 } 74 75 if (key->len != RSANUMWORDS) { 76 ERROR("Invalid key length %d\n", key->len); 77 fclose(f); 78 free(key); 79 return NULL; 80 } 81 82 fclose(f); 83 return key; 84} 85 86static int verify_table(char *signature, char *table, int table_length) 87{ 88 RSAPublicKey *key; 89 uint8_t hash_buf[SHA_DIGEST_SIZE]; 90 int retval = -1; 91 92 // Hash the table 93 SHA_hash((uint8_t*)table, table_length, hash_buf); 94 95 // Now get the public key from the keyfile 96 key = load_key(VERITY_TABLE_RSA_KEY); 97 if (!key) { 98 ERROR("Couldn't load verity keys"); 99 goto out; 100 } 101 102 // verify the result 103 if (!RSA_verify(key, 104 (uint8_t*) signature, 105 RSANUMBYTES, 106 (uint8_t*) hash_buf, 107 SHA_DIGEST_SIZE)) { 108 ERROR("Couldn't verify table."); 109 goto out; 110 } 111 112 retval = 0; 113 114out: 115 free(key); 116 return retval; 117} 118 119static int get_target_device_size(char *blk_device, uint64_t *device_size) 120{ 121 int data_device; 122 struct ext4_super_block sb; 123 struct fs_info info; 124 125 info.len = 0; /* Only len is set to 0 to ask the device for real size. */ 126 127 data_device = open(blk_device, O_RDONLY); 128 if (data_device < 0) { 129 ERROR("Error opening block device (%s)", strerror(errno)); 130 return -1; 131 } 132 133 if (lseek64(data_device, 1024, SEEK_SET) < 0) { 134 ERROR("Error seeking to superblock"); 135 close(data_device); 136 return -1; 137 } 138 139 if (read(data_device, &sb, sizeof(sb)) != sizeof(sb)) { 140 ERROR("Error reading superblock"); 141 close(data_device); 142 return -1; 143 } 144 145 ext4_parse_sb(&sb, &info); 146 *device_size = info.len; 147 148 close(data_device); 149 return 0; 150} 151 152static int read_verity_metadata(char *block_device, char **signature, char **table) 153{ 154 unsigned magic_number; 155 unsigned table_length; 156 uint64_t device_length; 157 int protocol_version; 158 FILE *device; 159 int retval = -1; 160 161 device = fopen(block_device, "r"); 162 if (!device) { 163 ERROR("Could not open block device %s (%s).\n", block_device, strerror(errno)); 164 goto out; 165 } 166 167 // find the start of the verity metadata 168 if (get_target_device_size(block_device, &device_length) < 0) { 169 ERROR("Could not get target device size.\n"); 170 goto out; 171 } 172 if (fseek(device, device_length, SEEK_SET) < 0) { 173 ERROR("Could not seek to start of verity metadata block.\n"); 174 goto out; 175 } 176 177 // check the magic number 178 if (!fread(&magic_number, sizeof(int), 1, device)) { 179 ERROR("Couldn't read magic number!\n"); 180 goto out; 181 } 182 if (magic_number != VERITY_METADATA_MAGIC_NUMBER) { 183 ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", device_length); 184 goto out; 185 } 186 187 // check the protocol version 188 if (!fread(&protocol_version, sizeof(int), 1, device)) { 189 ERROR("Couldn't read verity metadata protocol version!\n"); 190 goto out; 191 } 192 if (protocol_version != 0) { 193 ERROR("Got unknown verity metadata protocol version %d!\n", protocol_version); 194 goto out; 195 } 196 197 // get the signature 198 *signature = (char*) malloc(RSANUMBYTES * sizeof(char)); 199 if (!*signature) { 200 ERROR("Couldn't allocate memory for signature!\n"); 201 goto out; 202 } 203 if (!fread(*signature, RSANUMBYTES, 1, device)) { 204 ERROR("Couldn't read signature from verity metadata!\n"); 205 free(*signature); 206 goto out; 207 } 208 209 // get the size of the table 210 if (!fread(&table_length, sizeof(int), 1, device)) { 211 ERROR("Couldn't get the size of the verity table from metadata!\n"); 212 free(*signature); 213 goto out; 214 } 215 216 // get the table + null terminator 217 table_length += 1; 218 *table = malloc(table_length); 219 if(!*table) { 220 ERROR("Couldn't allocate memory for verity table!\n"); 221 goto out; 222 } 223 if (!fgets(*table, table_length, device)) { 224 ERROR("Couldn't read the verity table from metadata!\n"); 225 free(*table); 226 free(*signature); 227 goto out; 228 } 229 230 retval = 0; 231 232out: 233 if (device) 234 fclose(device); 235 return retval; 236} 237 238static void verity_ioctl_init(struct dm_ioctl *io, char *name, unsigned flags) 239{ 240 memset(io, 0, DM_BUF_SIZE); 241 io->data_size = DM_BUF_SIZE; 242 io->data_start = sizeof(struct dm_ioctl); 243 io->version[0] = 4; 244 io->version[1] = 0; 245 io->version[2] = 0; 246 io->flags = flags | DM_READONLY_FLAG; 247 if (name) { 248 strlcpy(io->name, name, sizeof(io->name)); 249 } 250} 251 252static int create_verity_device(struct dm_ioctl *io, char *name, int fd) 253{ 254 verity_ioctl_init(io, name, 1); 255 if (ioctl(fd, DM_DEV_CREATE, io)) { 256 ERROR("Error creating device mapping (%s)", strerror(errno)); 257 return -1; 258 } 259 return 0; 260} 261 262static int get_verity_device_name(struct dm_ioctl *io, char *name, int fd, char **dev_name) 263{ 264 verity_ioctl_init(io, name, 0); 265 if (ioctl(fd, DM_DEV_STATUS, io)) { 266 ERROR("Error fetching verity device number (%s)", strerror(errno)); 267 return -1; 268 } 269 int dev_num = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00); 270 if (asprintf(dev_name, "/dev/block/dm-%u", dev_num) < 0) { 271 ERROR("Error getting verity block device name (%s)", strerror(errno)); 272 return -1; 273 } 274 return 0; 275} 276 277static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table) 278{ 279 char *verity_params; 280 char *buffer = (char*) io; 281 uint64_t device_size = 0; 282 283 if (get_target_device_size(blockdev, &device_size) < 0) { 284 return -1; 285 } 286 287 verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG); 288 289 struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)]; 290 291 // set tgt arguments here 292 io->target_count = 1; 293 tgt->status=0; 294 tgt->sector_start=0; 295 tgt->length=device_size/512; 296 strcpy(tgt->target_type, "verity"); 297 298 // build the verity params here 299 verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec); 300 if (sprintf(verity_params, "%s", table) < 0) { 301 return -1; 302 } 303 304 // set next target boundary 305 verity_params += strlen(verity_params) + 1; 306 verity_params = (char*) (((unsigned long)verity_params + 7) & ~8); 307 tgt->next = verity_params - buffer; 308 309 // send the ioctl to load the verity table 310 if (ioctl(fd, DM_TABLE_LOAD, io)) { 311 ERROR("Error loading verity table (%s)", strerror(errno)); 312 return -1; 313 } 314 315 return 0; 316} 317 318static int resume_verity_table(struct dm_ioctl *io, char *name, int fd) 319{ 320 verity_ioctl_init(io, name, 0); 321 if (ioctl(fd, DM_DEV_SUSPEND, io)) { 322 ERROR("Error activating verity device (%s)", strerror(errno)); 323 return -1; 324 } 325 return 0; 326} 327 328static int test_access(char *device) { 329 int tries = 25; 330 while (tries--) { 331 if (!access(device, F_OK) || errno != ENOENT) { 332 return 0; 333 } 334 usleep(40 * 1000); 335 } 336 return -1; 337} 338 339int fs_mgr_setup_verity(struct fstab_rec *fstab) { 340 341 int retval = -1; 342 343 char *verity_blk_name; 344 char *verity_table; 345 char *verity_table_signature; 346 347 char buffer[DM_BUF_SIZE]; 348 struct dm_ioctl *io = (struct dm_ioctl *) buffer; 349 char *mount_point = basename(fstab->mount_point); 350 351 // set the dm_ioctl flags 352 io->flags |= 1; 353 io->target_count = 1; 354 355 // get the device mapper fd 356 int fd; 357 if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) { 358 ERROR("Error opening device mapper (%s)", strerror(errno)); 359 return retval; 360 } 361 362 // create the device 363 if (create_verity_device(io, mount_point, fd) < 0) { 364 ERROR("Couldn't create verity device!"); 365 goto out; 366 } 367 368 // get the name of the device file 369 if (get_verity_device_name(io, mount_point, fd, &verity_blk_name) < 0) { 370 ERROR("Couldn't get verity device number!"); 371 goto out; 372 } 373 374 // read the verity block at the end of the block device 375 if (read_verity_metadata(fstab->blk_device, 376 &verity_table_signature, 377 &verity_table) < 0) { 378 goto out; 379 } 380 381 // verify the signature on the table 382 if (verify_table(verity_table_signature, 383 verity_table, 384 strlen(verity_table)) < 0) { 385 goto out; 386 } 387 388 // load the verity mapping table 389 if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table) < 0) { 390 goto out; 391 } 392 393 // activate the device 394 if (resume_verity_table(io, mount_point, fd) < 0) { 395 goto out; 396 } 397 398 // assign the new verity block device as the block device 399 free(fstab->blk_device); 400 fstab->blk_device = verity_blk_name; 401 402 // make sure we've set everything up properly 403 if (test_access(fstab->blk_device) < 0) { 404 goto out; 405 } 406 407 retval = 0; 408 409out: 410 close(fd); 411 return retval; 412} 413