static char verifiedbootstate[VERITY_COMMANDLINE_PARAM_LENGTH];
static char veritymode[VERITY_COMMANDLINE_PARAM_LENGTH];
static char veritykeyid[VERITY_DEFAULT_KEY_ID_LENGTH];
+static char buildvariant[BUILD_VARIANT];
static bool target_added;
static bool verity_enabled = true;
.dtr = verity_dtr,
.map = verity_map,
.status = verity_status,
- .ioctl = verity_ioctl,
- .merge = verity_merge,
+ .prepare_ioctl = verity_prepare_ioctl,
.iterate_devices = verity_iterate_devices,
.io_hints = verity_io_hints,
};
__setup("veritykeyid=", verity_keyid_param);
+static int __init verity_buildvariant(char *line)
+{
+ strlcpy(buildvariant, line, sizeof(buildvariant));
+ return 1;
+}
+
+__setup("buildvariant=", verity_buildvariant);
+
static inline bool default_verity_key_id(void)
{
return veritykeyid[0] != '\0';
}
+static inline bool is_eng(void)
+{
+ static const char typeeng[] = "eng";
+
+ return !strncmp(buildvariant, typeeng, sizeof(typeeng));
+}
+
+static inline bool is_userdebug(void)
+{
+ static const char typeuserdebug[] = "userdebug";
+
+ return !strncmp(buildvariant, typeuserdebug, sizeof(typeuserdebug));
+}
+
+
static int table_extract_mpi_array(struct public_key_signature *pks,
const void *data, size_t len)
{
le32_to_cpu(header->version) != FEC_VERSION ||
le32_to_cpu(header->size) != sizeof(struct fec_header) ||
le32_to_cpu(header->roots) == 0 ||
- le32_to_cpu(header->roots) >= FEC_RSM ||
- offset < le32_to_cpu(header->fec_size) ||
- offset - le32_to_cpu(header->fec_size) !=
- le64_to_cpu(header->inp_size))
+ le32_to_cpu(header->roots) >= FEC_RSM)
return -EINVAL;
return 0;
bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
- if (IS_ERR(bdev)) {
+ if (IS_ERR_OR_NULL(bdev)) {
DMERR("bdev get error");
return PTR_ERR(bdev);
}
*metadata_offset = device_size - VERITY_METADATA_SIZE;
}
-static struct android_metadata *extract_metadata(dev_t dev,
- struct fec_header *fec)
+static int find_size(dev_t dev, u64 *device_size)
+{
+ struct block_device *bdev;
+
+ bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
+ if (IS_ERR_OR_NULL(bdev)) {
+ DMERR("blkdev_get_by_dev failed");
+ return PTR_ERR(bdev);
+ }
+
+ *device_size = i_size_read(bdev->bd_inode);
+ *device_size >>= SECTOR_SHIFT;
+
+ DMINFO("blkdev size in sectors: %llu", *device_size);
+ blkdev_put(bdev, FMODE_READ);
+ return 0;
+}
+
+static int verify_header(struct android_metadata_header *header)
+{
+ int retval = -EINVAL;
+
+ if (is_userdebug() && le32_to_cpu(header->magic_number) ==
+ VERITY_METADATA_MAGIC_DISABLE)
+ return VERITY_STATE_DISABLE;
+
+ if (!(le32_to_cpu(header->magic_number) ==
+ VERITY_METADATA_MAGIC_NUMBER) ||
+ (le32_to_cpu(header->magic_number) ==
+ VERITY_METADATA_MAGIC_DISABLE)) {
+ DMERR("Incorrect magic number");
+ return retval;
+ }
+
+ if (le32_to_cpu(header->protocol_version) !=
+ VERITY_METADATA_VERSION) {
+ DMERR("Unsupported version %u",
+ le32_to_cpu(header->protocol_version));
+ return retval;
+ }
+
+ return 0;
+}
+
+static int extract_metadata(dev_t dev, struct fec_header *fec,
+ struct android_metadata **metadata,
+ bool *verity_enabled)
{
struct block_device *bdev;
struct android_metadata_header *header;
- struct android_metadata *uninitialized_var(metadata);
int i;
u32 table_length, copy_length, offset;
u64 metadata_offset;
bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
- if (IS_ERR(bdev)) {
+ if (IS_ERR_OR_NULL(bdev)) {
DMERR("blkdev_get_by_dev failed");
- return ERR_CAST(bdev);
+ return -ENODEV;
}
find_metadata_offset(fec, bdev, &metadata_offset);
(1 << SECTOR_SHIFT), VERITY_METADATA_SIZE);
if (err) {
DMERR("Error while reading verity metadata");
- metadata = ERR_PTR(err);
goto blkdev_release;
}
le32_to_cpu(header->protocol_version),
le32_to_cpu(header->table_length));
- metadata = kzalloc(sizeof(*metadata), GFP_KERNEL);
- if (!metadata) {
+ err = verify_header(header);
+
+ if (err == VERITY_STATE_DISABLE) {
+ DMERR("Mounting root with verity disabled");
+ *verity_enabled = false;
+ /* we would still have to read the metadata to figure out
+ * the data blocks size. Or may be could map the entire
+ * partition similar to mounting the device.
+ *
+ * Reset error as well as the verity_enabled flag is changed.
+ */
+ err = 0;
+ } else if (err)
+ goto free_header;
+
+ *metadata = kzalloc(sizeof(**metadata), GFP_KERNEL);
+ if (!*metadata) {
DMERR("kzalloc for metadata failed");
err = -ENOMEM;
goto free_header;
}
- metadata->header = header;
+ (*metadata)->header = header;
table_length = le32_to_cpu(header->table_length);
if (table_length == 0 ||
table_length > (VERITY_METADATA_SIZE -
- sizeof(struct android_metadata_header)))
+ sizeof(struct android_metadata_header))) {
+ DMERR("table_length too long");
+ err = -EINVAL;
goto free_metadata;
+ }
- metadata->verity_table = kzalloc(table_length + 1, GFP_KERNEL);
+ (*metadata)->verity_table = kzalloc(table_length + 1, GFP_KERNEL);
- if (!metadata->verity_table) {
+ if (!(*metadata)->verity_table) {
DMERR("kzalloc verity_table failed");
err = -ENOMEM;
goto free_metadata;
if (sizeof(struct android_metadata_header) +
table_length <= PAGE_SIZE) {
- memcpy(metadata->verity_table, page_address(payload.page_io[0])
+ memcpy((*metadata)->verity_table,
+ page_address(payload.page_io[0])
+ sizeof(struct android_metadata_header),
table_length);
} else {
copy_length = PAGE_SIZE -
sizeof(struct android_metadata_header);
- memcpy(metadata->verity_table, page_address(payload.page_io[0])
+ memcpy((*metadata)->verity_table,
+ page_address(payload.page_io[0])
+ sizeof(struct android_metadata_header),
copy_length);
table_length -= copy_length;
i = 1;
while (table_length != 0) {
if (table_length > PAGE_SIZE) {
- memcpy(metadata->verity_table + offset,
+ memcpy((*metadata)->verity_table + offset,
page_address(payload.page_io[i]),
PAGE_SIZE);
offset += PAGE_SIZE;
table_length -= PAGE_SIZE;
} else {
- memcpy(metadata->verity_table + offset,
+ memcpy((*metadata)->verity_table + offset,
page_address(payload.page_io[i]),
table_length);
table_length = 0;
i++;
}
}
- metadata->verity_table[table_length] = '\0';
+ (*metadata)->verity_table[table_length] = '\0';
+ DMINFO("verity_table: %s", (*metadata)->verity_table);
goto free_payload;
free_metadata:
- kfree(metadata);
+ kfree(*metadata);
free_header:
kfree(header);
- metadata = ERR_PTR(err);
free_payload:
for (i = 0; i < payload.number_of_pages; i++)
if (payload.page_io[i])
__free_page(payload.page_io[i]);
kfree(payload.page_io);
-
- DMINFO("verity_table: %s", metadata->verity_table);
blkdev_release:
blkdev_put(bdev, FMODE_READ);
- return metadata;
+ return err;
}
/* helper functions to extract properties from dts */
return value;
}
-static bool is_unlocked(void)
-{
- static const char unlocked[] = "orange";
- static const char verified_boot_prop[] = "verifiedbootstate";
- const char *value;
-
- value = find_dt_value(verified_boot_prop);
- if (!value)
- value = verifiedbootstate;
-
- return !strncmp(value, unlocked, sizeof(unlocked) - 1);
-}
-
static int verity_mode(void)
{
static const char enforcing[] = "enforcing";
return DM_VERITY_MODE_EIO;
}
-static int verify_header(struct android_metadata_header *header)
-{
- int retval = -EINVAL;
-
- if (is_unlocked() && le32_to_cpu(header->magic_number) ==
- VERITY_METADATA_MAGIC_DISABLE) {
- retval = VERITY_STATE_DISABLE;
- return retval;
- }
-
- if (!(le32_to_cpu(header->magic_number) ==
- VERITY_METADATA_MAGIC_NUMBER) ||
- (le32_to_cpu(header->magic_number) ==
- VERITY_METADATA_MAGIC_DISABLE)) {
- DMERR("Incorrect magic number");
- return retval;
- }
-
- if (le32_to_cpu(header->protocol_version) !=
- VERITY_METADATA_VERSION) {
- DMERR("Unsupported version %u",
- le32_to_cpu(header->protocol_version));
- return retval;
- }
-
- return 0;
-}
-
static int verify_verity_signature(char *key_id,
struct android_metadata *metadata)
{
android_verity_target.dtr = dm_linear_dtr,
android_verity_target.map = dm_linear_map,
android_verity_target.status = dm_linear_status,
- android_verity_target.ioctl = dm_linear_ioctl,
- android_verity_target.merge = dm_linear_merge,
+ android_verity_target.prepare_ioctl = dm_linear_prepare_ioctl,
android_verity_target.iterate_devices = dm_linear_iterate_devices,
android_verity_target.io_hints = NULL;
static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
{
dev_t uninitialized_var(dev);
- struct android_metadata *uninitialized_var(metadata);
+ struct android_metadata *metadata = NULL;
int err = 0, i, mode;
char *key_id, *table_ptr, dummy, *target_device,
*verity_table_args[VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS];
struct fec_ecc_metadata uninitialized_var(ecc);
char buf[FEC_ARG_LENGTH], *buf_ptr;
unsigned long long tmpll;
+ u64 uninitialized_var(device_size);
if (argc == 1) {
/* Use the default keyid */
if (default_verity_key_id())
key_id = veritykeyid;
- else {
+ else if (!is_eng()) {
DMERR("veritykeyid= is not set");
handle_error();
return -EINVAL;
return -EINVAL;
}
- strreplace(key_id, '#', ' ');
target_device = argv[0];
dev = name_to_dev_t(target_device);
return -EINVAL;
}
+ if (is_eng()) {
+ err = find_size(dev, &device_size);
+ if (err) {
+ DMERR("error finding bdev size");
+ handle_error();
+ return err;
+ }
+
+ ti->len = device_size;
+ err = add_as_linear_device(ti, target_device);
+ if (err) {
+ handle_error();
+ return err;
+ }
+ verity_enabled = false;
+ return 0;
+ }
+
+ strreplace(key_id, '#', ' ');
+
DMINFO("key:%s dev:%s", key_id, target_device);
if (extract_fec_header(dev, &fec, &ecc)) {
return -EINVAL;
}
- metadata = extract_metadata(dev, &fec);
+ err = extract_metadata(dev, &fec, &metadata, &verity_enabled);
- if (IS_ERR(metadata)) {
+ if (err) {
DMERR("Error while extracting metadata");
handle_error();
- return -EINVAL;
- }
-
- err = verify_header(metadata->header);
-
- if (err == VERITY_STATE_DISABLE) {
- DMERR("Mounting root with verity disabled");
- verity_enabled = false;
- /* we would still have to parse the args to figure out
- * the data blocks size. Or may be could map the entire
- * partition similar to mounting the device.
- */
- } else if (err) {
- DMERR("Verity header handle error");
- handle_error();
goto free_metadata;
}
}
free_metadata:
- kfree(metadata->header);
- kfree(metadata->verity_table);
+ if (metadata) {
+ kfree(metadata->header);
+ kfree(metadata->verity_table);
+ }
kfree(metadata);
return err;
}
}
file = debugfs_create_bool("target_added", S_IRUGO, debug_dir,
- (u32 *)&target_added);
+ &target_added);
if (IS_ERR_OR_NULL(file)) {
DMERR("Cannot create android_verity debugfs directory: %ld",
}
file = debugfs_create_bool("verity_enabled", S_IRUGO, debug_dir,
- (u32 *)&verity_enabled);
+ &verity_enabled);
if (IS_ERR_OR_NULL(file)) {
DMERR("Cannot create android_verity debugfs directory: %ld",