Skip to content

Commit

Permalink
ANDROID: android-verity: Make it work with newer kernels
Browse files Browse the repository at this point in the history
 Fixed bio API calls as they changed from 4.4 to 4.9.
 Fixed the driver to use the new verify_signature_one() API.
 Remove the dead code resulted from the rebase.

Bug: 72722987
Test: Build and boot hikey with system partition mounted as root using
      android-verity
Signed-off-by: Sandeep Patil <[email protected]>

Change-Id: I1e29111d57b62f0451404c08d49145039dd00737
  • Loading branch information
patils authored and Alistair Strachan committed Jul 26, 2018
1 parent cded278 commit 76905cc
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 111 deletions.
194 changes: 85 additions & 109 deletions drivers/md/dm-android-verity.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

#include <asm/setup.h>
#include <crypto/hash.h>
#include <crypto/hash_info.h>
#include <crypto/public_key.h>
#include <crypto/sha.h>
#include <keys/asymmetric-type.h>
Expand Down Expand Up @@ -122,75 +123,6 @@ static inline bool is_unlocked(void)
return !strncmp(verifiedbootstate, unlocked, sizeof(unlocked));
}

static int table_extract_mpi_array(struct public_key_signature *pks,
const void *data, size_t len)
{
MPI mpi = mpi_read_raw_data(data, len);

if (!mpi) {
DMERR("Error while allocating mpi array");
return -ENOMEM;
}

pks->mpi[0] = mpi;
pks->nr_mpi = 1;
return 0;
}

static struct public_key_signature *table_make_digest(
enum hash_algo hash,
const void *table,
unsigned long table_len)
{
struct public_key_signature *pks = NULL;
struct crypto_shash *tfm;
struct shash_desc *desc;
size_t digest_size, desc_size;
int ret;

/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
if (IS_ERR(tfm))
return ERR_CAST(tfm);

desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
digest_size = crypto_shash_digestsize(tfm);

/* We allocate the hash operational data storage on the end of out
* context data and the digest output buffer on the end of that.
*/
ret = -ENOMEM;
pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL);
if (!pks)
goto error;

pks->pkey_hash_algo = hash;
pks->digest = (u8 *)pks + sizeof(*pks) + desc_size;
pks->digest_size = digest_size;

desc = (struct shash_desc *)(pks + 1);
desc->tfm = tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;

ret = crypto_shash_init(desc);
if (ret < 0)
goto error;

ret = crypto_shash_finup(desc, table, table_len, pks->digest);
if (ret < 0)
goto error;

crypto_free_shash(tfm);
return pks;

error:
kfree(pks);
crypto_free_shash(tfm);
return ERR_PTR(ret);
}

static int read_block_dev(struct bio_read *payload, struct block_device *bdev,
sector_t offset, int length)
{
Expand All @@ -205,8 +137,9 @@ static int read_block_dev(struct bio_read *payload, struct block_device *bdev,
return -ENOMEM;
}

bio->bi_bdev = bdev;
bio_set_dev(bio, bdev);
bio->bi_iter.bi_sector = offset;
bio_set_op_attrs(bio, REQ_OP_READ, 0);

payload->page_io = kzalloc(sizeof(struct page *) *
payload->number_of_pages, GFP_KERNEL);
Expand All @@ -230,7 +163,7 @@ static int read_block_dev(struct bio_read *payload, struct block_device *bdev,
}
}

if (!submit_bio_wait(READ, bio))
if (!submit_bio_wait(bio))
/* success */
goto free_bio;
DMERR("bio read failed");
Expand Down Expand Up @@ -567,62 +500,106 @@ static int verity_mode(void)
return DM_VERITY_MODE_EIO;
}

static void handle_error(void)
{
int mode = verity_mode();
if (mode == DM_VERITY_MODE_RESTART) {
DMERR("triggering restart");
kernel_restart("dm-verity device corrupted");
} else {
DMERR("Mounting verity root failed");
}
}

static struct public_key_signature *table_make_digest(
enum hash_algo hash,
const void *table,
unsigned long table_len)
{
struct public_key_signature *pks = NULL;
struct crypto_shash *tfm;
struct shash_desc *desc;
size_t digest_size, desc_size;
int ret;

/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
if (IS_ERR(tfm))
return ERR_CAST(tfm);

desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
digest_size = crypto_shash_digestsize(tfm);

/* We allocate the hash operational data storage on the end of out
* context data and the digest output buffer on the end of that.
*/
ret = -ENOMEM;
pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL);
if (!pks)
goto error;

pks->pkey_algo = "rsa";
pks->hash_algo = hash_algo_name[hash];
pks->digest = (u8 *)pks + sizeof(*pks) + desc_size;
pks->digest_size = digest_size;

desc = (struct shash_desc *)(pks + 1);
desc->tfm = tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;

ret = crypto_shash_init(desc);
if (ret < 0)
goto error;

ret = crypto_shash_finup(desc, table, table_len, pks->digest);
if (ret < 0)
goto error;

crypto_free_shash(tfm);
return pks;

error:
kfree(pks);
crypto_free_shash(tfm);
return ERR_PTR(ret);
}


static int verify_verity_signature(char *key_id,
struct android_metadata *metadata)
{
key_ref_t key_ref;
struct key *key;
struct public_key_signature *pks = NULL;
int retval = -EINVAL;

key_ref = keyring_search(make_key_ref(system_trusted_keyring, 1),
&key_type_asymmetric, key_id);

if (IS_ERR(key_ref)) {
DMERR("keyring: key not found");
return -ENOKEY;
}

key = key_ref_to_ptr(key_ref);
if (!key_id)
goto error;

pks = table_make_digest(HASH_ALGO_SHA256,
(const void *)metadata->verity_table,
le32_to_cpu(metadata->header->table_length));

if (IS_ERR(pks)) {
DMERR("hashing failed");
retval = PTR_ERR(pks);
pks = NULL;
goto error;
}

retval = table_extract_mpi_array(pks, &metadata->header->signature[0],
RSANUMBYTES);
if (retval < 0) {
DMERR("Error extracting mpi %d", retval);
pks->s = kmemdup(&metadata->header->signature[0], RSANUMBYTES, GFP_KERNEL);
if (!pks->s) {
DMERR("Error allocating memory for signature");
goto error;
}
pks->s_size = RSANUMBYTES;

retval = verify_signature(key, pks);
mpi_free(pks->rsa.s);
retval = verify_signature_one(pks, NULL, key_id);
kfree(pks->s);
error:
kfree(pks);
key_put(key);

return retval;
}

static void handle_error(void)
{
int mode = verity_mode();
if (mode == DM_VERITY_MODE_RESTART) {
DMERR("triggering restart");
kernel_restart("dm-verity device corrupted");
} else {
DMERR("Mounting verity root failed");
}
}

static inline bool test_mult_overflow(sector_t a, u32 b)
{
sector_t r = (sector_t)~0ULL;
Expand Down Expand Up @@ -696,8 +673,8 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
dev_t uninitialized_var(dev);
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];
char *key_id = NULL, *table_ptr, dummy, *target_device;
char *verity_table_args[VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS];
/* One for specifying number of opt args and one for mode */
sector_t data_sectors;
u32 data_block_size;
Expand Down Expand Up @@ -879,12 +856,11 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
}

err = verity_ctr(ti, no_of_args, verity_table_args);

if (err)
DMERR("android-verity failed to mount as verity target");
else {
if (err) {
DMERR("android-verity failed to create a verity target");
} else {
target_added = true;
DMINFO("android-verity mounted as verity target");
DMINFO("android-verity created as verity target");
}

free_metadata:
Expand Down
5 changes: 3 additions & 2 deletions drivers/md/dm-android-verity.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,9 @@ extern int dm_linear_prepare_ioctl(struct dm_target *ti,
extern int dm_linear_iterate_devices(struct dm_target *ti,
iterate_devices_callout_fn fn, void *data);
extern int dm_linear_ctr(struct dm_target *ti, unsigned int argc, char **argv);
extern long dm_linear_dax_direct_access(struct dm_target *ti, sector_t sector,
void **kaddr, pfn_t *pfn, long size);
extern long dm_linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
long nr_pages, void **kaddr,
pfn_t *pfn);
extern size_t dm_linear_dax_copy_from_iter(struct dm_target *ti, pgoff_t pgoff,
void *addr, size_t bytes, struct iov_iter *i);
#endif /* DM_ANDROID_VERITY_H */

0 comments on commit 76905cc

Please sign in to comment.