13ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra/* 23ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * Copyright (C) 2013 The Android Open Source Project 33ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * 43ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * Licensed under the Apache License, Version 2.0 (the "License"); 53ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * you may not use this file except in compliance with the License. 63ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * You may obtain a copy of the License at 73ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * 83ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * http://www.apache.org/licenses/LICENSE-2.0 93ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * 103ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * Unless required by applicable law or agreed to in writing, software 113ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * distributed under the License is distributed on an "AS IS" BASIS, 123ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * See the License for the specific language governing permissions and 143ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * limitations under the License. 153ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra */ 163ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 173ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <stdio.h> 183ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <stdlib.h> 193ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <string.h> 203ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <unistd.h> 213ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <fcntl.h> 223ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <ctype.h> 233ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <sys/mount.h> 243ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <sys/stat.h> 253ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <errno.h> 263ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <sys/types.h> 273ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <sys/wait.h> 283ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <libgen.h> 293ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <time.h> 303ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 313ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <private/android_filesystem_config.h> 323ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <logwrap/logwrap.h> 333ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 343ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include "mincrypt/rsa.h" 353ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include "mincrypt/sha.h" 363ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include "mincrypt/sha256.h" 373ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 383ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include "ext4_utils.h" 393ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include "ext4.h" 403ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 413ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include "fs_mgr_priv.h" 423ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include "fs_mgr_priv_verity.h" 433ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 443ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#define VERITY_METADATA_SIZE 32768 453ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001 463ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#define VERITY_TABLE_RSA_KEY "/verity_key" 473ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 483ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condraextern struct fs_info info; 493ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 503ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condrastatic RSAPublicKey *load_key(char *path) 513ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra{ 523ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra FILE *f; 533ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra RSAPublicKey *key; 543ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 553ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra key = malloc(sizeof(RSAPublicKey)); 563ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!key) { 573ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Can't malloc key\n"); 583ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return NULL; 593ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 603ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 613ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra f = fopen(path, "r"); 623ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!f) { 633ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Can't open '%s'\n", path); 643ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra free(key); 653ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return NULL; 663ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 673ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 683ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!fread(key, sizeof(*key), 1, f)) { 693ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Could not read key!"); 703ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra fclose(f); 713ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra free(key); 723ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return NULL; 733ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 743ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 753ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (key->len != RSANUMWORDS) { 763ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Invalid key length %d\n", key->len); 773ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra fclose(f); 783ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra free(key); 793ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return NULL; 803ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 813ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 823ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra fclose(f); 833ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return key; 843ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra} 853ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 863ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condrastatic int verify_table(char *signature, char *table, int table_length) 873ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra{ 883ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra int fd; 893ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra RSAPublicKey *key; 903ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra uint8_t hash_buf[SHA_DIGEST_SIZE]; 913ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra int retval = -1; 923ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 933ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // Hash the table 943ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra SHA_hash((uint8_t*)table, table_length, hash_buf); 953ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 963ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // Now get the public key from the keyfile 973ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra key = load_key(VERITY_TABLE_RSA_KEY); 983ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!key) { 993ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Couldn't load verity keys"); 1003ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 1013ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 1023ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1033ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // verify the result 1043ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!RSA_verify(key, 1053ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra (uint8_t*) signature, 1063ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra RSANUMBYTES, 1073ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra (uint8_t*) hash_buf, 1083ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra SHA_DIGEST_SIZE)) { 1093ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Couldn't verify table."); 1103ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 1113ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 1123ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1133ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra retval = 0; 1143ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1153ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condraout: 1163ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra free(key); 1173ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return retval; 1183ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra} 1193ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1203ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condrastatic int get_target_device_size(char *blk_device, uint64_t *device_size) 1213ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra{ 1223ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra int data_device; 1233ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra struct ext4_super_block sb; 1243ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1253ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra data_device = open(blk_device, O_RDONLY); 1263ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (data_device < 0) { 1273ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Error opening block device (%s)", strerror(errno)); 1283ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return -1; 1293ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 1303ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1313ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (lseek64(data_device, 1024, SEEK_SET) < 0) { 1323ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Error seeking to superblock"); 1333ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra close(data_device); 1343ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return -1; 1353ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 1363ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1373ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (read(data_device, &sb, sizeof(sb)) != sizeof(sb)) { 1383ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Error reading superblock"); 1393ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra close(data_device); 1403ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return -1; 1413ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 1423ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1433ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ext4_parse_sb(&sb); 1443ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra *device_size = info.len; 1453ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1463ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra close(data_device); 1473ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return 0; 1483ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra} 1493ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1503ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condrastatic int read_verity_metadata(char *block_device, char **signature, char **table) 1513ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra{ 1523ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra unsigned magic_number; 1533ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra unsigned table_length; 1543ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra uint64_t device_length; 1553ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra int protocol_version; 1563ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra FILE *device; 1573ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra int retval = -1; 1583ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1593ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra device = fopen(block_device, "r"); 1603ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!device) { 1613ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Could not open block device %s (%s).\n", block_device, strerror(errno)); 1623ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 1633ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 1643ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1653ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // find the start of the verity metadata 1663ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (get_target_device_size(block_device, &device_length) < 0) { 1673ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Could not get target device size.\n"); 1683ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 1693ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 1703ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (fseek(device, device_length, SEEK_SET) < 0) { 1713ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Could not seek to start of verity metadata block.\n"); 1723ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 1733ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 1743ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1753ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // check the magic number 1763ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!fread(&magic_number, sizeof(int), 1, device)) { 1773ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Couldn't read magic number!\n"); 1783ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 1793ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 1803ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (magic_number != VERITY_METADATA_MAGIC_NUMBER) { 1813ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Couldn't find verity metadata at offset %llu!\n", device_length); 1823ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 1833ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 1843ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1853ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // check the protocol version 1863ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!fread(&protocol_version, sizeof(int), 1, device)) { 1873ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Couldn't read verity metadata protocol version!\n"); 1883ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 1893ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 1903ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (protocol_version != 0) { 1913ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Got unknown verity metadata protocol version %d!\n", protocol_version); 1923ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 1933ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 1943ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 1953ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // get the signature 1963ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra *signature = (char*) malloc(RSANUMBYTES * sizeof(char)); 1973ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!*signature) { 1983ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Couldn't allocate memory for signature!\n"); 1993ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 2003ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 2013ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!fread(*signature, RSANUMBYTES, 1, device)) { 2023ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Couldn't read signature from verity metadata!\n"); 2033ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra free(*signature); 2043ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 2053ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 2063ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2073ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // get the size of the table 2083ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!fread(&table_length, sizeof(int), 1, device)) { 2093ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Couldn't get the size of the verity table from metadata!\n"); 2103ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra free(*signature); 2113ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 2123ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 2133ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2143ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // get the table + null terminator 2153ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra table_length += 1; 2163ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra *table = malloc(table_length); 2173ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if(!*table) { 2183ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Couldn't allocate memory for verity table!\n"); 2193ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 2203ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 2213ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!fgets(*table, table_length, device)) { 2223ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Couldn't read the verity table from metadata!\n"); 2233ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra free(*table); 2243ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra free(*signature); 2253ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 2263ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 2273ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2283ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra retval = 0; 2293ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2303ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condraout: 2313ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (device) 2323ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra fclose(device); 2333ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return retval; 2343ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra} 2353ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2363ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condrastatic void verity_ioctl_init(struct dm_ioctl *io, char *name, unsigned flags) 2373ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra{ 2383ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra memset(io, 0, DM_BUF_SIZE); 2393ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra io->data_size = DM_BUF_SIZE; 2403ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra io->data_start = sizeof(struct dm_ioctl); 2413ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra io->version[0] = 4; 2423ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra io->version[1] = 0; 2433ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra io->version[2] = 0; 2443ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra io->flags = flags | DM_READONLY_FLAG; 2453ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (name) { 2463ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra strlcpy(io->name, name, sizeof(io->name)); 2473ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 2483ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra} 2493ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2503ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condrastatic int create_verity_device(struct dm_ioctl *io, char *name, int fd) 2513ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra{ 2523ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra verity_ioctl_init(io, name, 1); 2533ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (ioctl(fd, DM_DEV_CREATE, io)) { 2543ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Error creating device mapping (%s)", strerror(errno)); 2553ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return -1; 2563ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 2573ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return 0; 2583ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra} 2593ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2603ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condrastatic int get_verity_device_name(struct dm_ioctl *io, char *name, int fd, char **dev_name) 2613ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra{ 2623ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra verity_ioctl_init(io, name, 0); 2633ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (ioctl(fd, DM_DEV_STATUS, io)) { 2643ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Error fetching verity device number (%s)", strerror(errno)); 2653ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return -1; 2663ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 2673ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra int dev_num = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00); 2683ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (asprintf(dev_name, "/dev/block/dm-%u", dev_num) < 0) { 2693ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Error getting verity block device name (%s)", strerror(errno)); 2703ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return -1; 2713ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 2723ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return 0; 2733ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra} 2743ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2753ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condrastatic int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table) 2763ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra{ 2773ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra char *verity_params; 2783ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra char *buffer = (char*) io; 2793ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra uint64_t device_size = 0; 2803ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2813ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (get_target_device_size(blockdev, &device_size) < 0) { 2823ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return -1; 2833ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 2843ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2853ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG); 2863ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2873ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)]; 2883ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2893ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // set tgt arguments here 2903ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra io->target_count = 1; 2913ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra tgt->status=0; 2923ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra tgt->sector_start=0; 2933ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra tgt->length=device_size/512; 2943ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra strcpy(tgt->target_type, "verity"); 2953ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 2963ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // build the verity params here 2973ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec); 2983ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (sprintf(verity_params, "%s", table) < 0) { 2993ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return -1; 3003ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 3013ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3023ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // set next target boundary 3033ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra verity_params += strlen(verity_params) + 1; 3043ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra verity_params = (char*) (((unsigned long)verity_params + 7) & ~8); 3053ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra tgt->next = verity_params - buffer; 3063ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3073ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // send the ioctl to load the verity table 3083ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (ioctl(fd, DM_TABLE_LOAD, io)) { 3093ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Error loading verity table (%s)", strerror(errno)); 3103ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return -1; 3113ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 3123ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3133ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return 0; 3143ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra} 3153ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3163ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condrastatic int resume_verity_table(struct dm_ioctl *io, char *name, int fd) 3173ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra{ 3183ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra verity_ioctl_init(io, name, 0); 3193ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (ioctl(fd, DM_DEV_SUSPEND, io)) { 3203ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Error activating verity device (%s)", strerror(errno)); 3213ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return -1; 3223ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 3233ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return 0; 3243ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra} 3253ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3263ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condrastatic int test_access(char *device) { 3273ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra int tries = 25; 3283ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra while (tries--) { 3293ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (!access(device, F_OK) || errno != ENOENT) { 3303ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return 0; 3313ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 3323ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra usleep(40 * 1000); 3333ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 3343ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return -1; 3353ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra} 3363ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3373ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condraint fs_mgr_setup_verity(struct fstab_rec *fstab) { 3383ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3393ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra int retval = -1; 3403ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3413ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra char *verity_blk_name; 3423ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra char *verity_table; 3433ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra char *verity_table_signature; 3443ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3453ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra char buffer[DM_BUF_SIZE]; 3463ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra struct dm_ioctl *io = (struct dm_ioctl *) buffer; 3473ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra char *mount_point = basename(fstab->mount_point); 3483ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3493ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // set the dm_ioctl flags 3503ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra io->flags |= 1; 3513ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra io->target_count = 1; 3523ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3533ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // get the device mapper fd 3543ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra int fd; 3553ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) { 3563ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Error opening device mapper (%s)", strerror(errno)); 3573ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return retval; 3583ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 3593ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3603ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // create the device 3613ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (create_verity_device(io, mount_point, fd) < 0) { 3623ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Couldn't create verity device!"); 3633ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 3643ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 3653ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3663ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // get the name of the device file 3673ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (get_verity_device_name(io, mount_point, fd, &verity_blk_name) < 0) { 3683ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra ERROR("Couldn't get verity device number!"); 3693ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 3703ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 3713ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3723ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // read the verity block at the end of the block device 3733ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (read_verity_metadata(fstab->blk_device, 3743ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra &verity_table_signature, 3753ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra &verity_table) < 0) { 3763ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 3773ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 3783ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3793ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // verify the signature on the table 3803ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (verify_table(verity_table_signature, 3813ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra verity_table, 3823ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra strlen(verity_table)) < 0) { 3833ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 3843ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 3853ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3863ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // load the verity mapping table 3873ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table) < 0) { 3883ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 3893ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 3903ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3913ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // activate the device 3923ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (resume_verity_table(io, mount_point, fd) < 0) { 3933ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 3943ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 3953ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 3963ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // assign the new verity block device as the block device 3973ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra free(fstab->blk_device); 3983ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra fstab->blk_device = verity_blk_name; 3993ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 4003ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra // make sure we've set everything up properly 4013ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra if (test_access(fstab->blk_device) < 0) { 4023ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra goto out; 4033ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra } 4043ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 4053ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra retval = 0; 4063ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra 4073ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condraout: 4083ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra close(fd); 4093ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra return retval; 4103ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra} 411