[PATCH] avb: Extend support to non-eMMC interfaces

Alistair Delva adelva at google.com
Tue Oct 11 22:40:34 CEST 2022


On Mon, Oct 10, 2022 at 7:53 AM Mattijs Korpershoek
<mkorpershoek at baylibre.com> wrote:
>
> Hi Alistair,
>
> Thank you for your patch.
>
> On lun., sept. 26, 2022 at 22:02, Alistair Delva <adelva at google.com> wrote:
>
> > From: Jiyong Park <jiyong at google.com>
> >
> > Previously Android AVB supported block devices only on eMMC. This change
> > eliminates the restriction by using the generic block driver model.
> >
> > The `avb init' command is modified to accept another parameter which
> > specifies the interface type. e.g., `avb init virtio 0' initializes
> > avb for the first (0) disk that is accessible via the virtio interface.
> >
> > [adelva: The "avb init" command is updated directly, as this is
> > considered a "debug command" that can't be usefully used in u-boot
> > scripts.]
>
> It seems that:
> * include/configs/ti_omap5_common.h
> * include/configs/meson64_android.h
> * configs/total_compute_defconfig
>
> All call "avb init"
>
> Aren't we breaking these boot scripts with this change?
>
> Since all of them used mmc before, it should be trivial to patch these
> environments as well.
> If you do so, please cc me in next version so I can give this a try on
> the khadas vim3l board.

Sure, I'll do that and send a v2.

> Maybe those devices are doing the wrong thing though. since this is
> considered a debug command I imagine we should not be calling this at
> all.
> If so, do you have any alternatives in mind?

Yes, sorry. My rationale was confusing. We have more patches to
upstream which will explain the reasoning better:

"data from boot and vendor_boot partitions are loaded only once for
the verification. After the verification is done, the read data is
directly copied to the load addresses instead of doing the I/O again
from the disk. This is to prevent a TOCTOU issue where attacker provides
different data for verification and actual booting."

So yes, what these env files do for now isn't safe, but there isn't a
good upstream alternative. Anyway, this problem isn't related to what
this patch is doing. So, I should update them for now.

> >
> > Signed-off-by: Alistair Delva <adelva at google.com>
> > Cc: Igor Opaniuk <igor.opaniuk at gmail.com>
> > Cc: Ram Muthiah <rammuthiah at google.com>
> > Cc: Jiyong Park <jiyong at google.com>
> > Cc: Simon Glass <sjg at chromium.org>
> > ---
> >  cmd/avb.c            |  16 ++++---
> >  common/Kconfig       |   1 -
> >  common/avb_verify.c  | 105 +++++++++++++++++++++----------------------
> >  include/avb_verify.h |  31 ++++---------
>
> Should we also update the documentation in doc/android/avb2.rst ?

Will do.

> I also think this might break:
> test/py/tests/test_android/test_avb.py

I'll update it.

> >  4 files changed, 69 insertions(+), 84 deletions(-)
> >
> > diff --git a/cmd/avb.c b/cmd/avb.c
> > index 783f51b816..8bffe49011 100644
> > --- a/cmd/avb.c
> > +++ b/cmd/avb.c
> > @@ -10,24 +10,25 @@
> >  #include <env.h>
> >  #include <image.h>
> >  #include <malloc.h>
> > -#include <mmc.h>
> >
> >  #define AVB_BOOTARGS "avb_bootargs"
> >  static struct AvbOps *avb_ops;
> >
> >  int do_avb_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
> >  {
> > -     unsigned long mmc_dev;
> > +     const char *iface;
> > +     const char *devnum;
> >
> > -     if (argc != 2)
> > +     if (argc != 3)
> >               return CMD_RET_USAGE;
> >
> > -     mmc_dev = hextoul(argv[1], NULL);
> > +     iface = argv[1];
> > +     devnum = argv[2];
> >
> >       if (avb_ops)
> >               avb_ops_free(avb_ops);
> >
> > -     avb_ops = avb_ops_alloc(mmc_dev);
> > +     avb_ops = avb_ops_alloc(iface, devnum);
> >       if (avb_ops)
> >               return CMD_RET_SUCCESS;
> >
> > @@ -419,7 +420,7 @@ int do_avb_write_pvalue(struct cmd_tbl *cmdtp, int flag, int argc,
> >  }
> >
> >  static struct cmd_tbl cmd_avb[] = {
> > -     U_BOOT_CMD_MKENT(init, 2, 0, do_avb_init, "", ""),
> > +     U_BOOT_CMD_MKENT(init, 3, 0, do_avb_init, "", ""),
> >       U_BOOT_CMD_MKENT(read_rb, 2, 0, do_avb_read_rb, "", ""),
> >       U_BOOT_CMD_MKENT(write_rb, 3, 0, do_avb_write_rb, "", ""),
> >       U_BOOT_CMD_MKENT(is_unlocked, 1, 0, do_avb_is_unlocked, "", ""),
> > @@ -455,7 +456,8 @@ static int do_avb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
> >  U_BOOT_CMD(
> >       avb, 29, 0, do_avb,
> >       "Provides commands for testing Android Verified Boot 2.0 functionality",
> > -     "init <dev> - initialize avb2 for <dev>\n"
> > +     "init <interface> <devnum> - initialize avb2 for the disk <devnum> which\n"
> > +     "    is on the interface <interface>\n"
> >       "avb read_rb <num> - read rollback index at location <num>\n"
> >       "avb write_rb <num> <rb> - write rollback index <rb> to <num>\n"
> >       "avb is_unlocked - returns unlock status of the device\n"
> > diff --git a/common/Kconfig b/common/Kconfig
> > index ebee856e56..a66060767c 100644
> > --- a/common/Kconfig
> > +++ b/common/Kconfig
> > @@ -703,7 +703,6 @@ config HASH
> >  config AVB_VERIFY
> >       bool "Build Android Verified Boot operations"
> >       depends on LIBAVB
> > -     depends on MMC
> >       depends on PARTITION_UUIDS
> >       help
> >         This option enables compilation of bootloader-dependent operations,
> > diff --git a/common/avb_verify.c b/common/avb_verify.c
> > index 0520a71455..d30bbb5726 100644
> > --- a/common/avb_verify.c
> > +++ b/common/avb_verify.c
> > @@ -253,10 +253,10 @@ char *avb_set_enforce_verity(const char *cmdline)
> >
> >  /**
> >   * ============================================================================
> > - * IO(mmc) auxiliary functions
> > + * IO auxiliary functions
> >   * ============================================================================
> >   */
> > -static unsigned long mmc_read_and_flush(struct mmc_part *part,
> > +static unsigned long blk_read_and_flush(struct avb_part *part,
> >                                       lbaint_t start,
> >                                       lbaint_t sectors,
> >                                       void *buffer)
> > @@ -291,7 +291,7 @@ static unsigned long mmc_read_and_flush(struct mmc_part *part,
> >               tmp_buf = buffer;
> >       }
> >
> > -     blks = blk_dread(part->mmc_blk,
> > +     blks = blk_dread(part->blk,
> >                        start, sectors, tmp_buf);
> >       /* flush cache after read */
> >       flush_cache((ulong)tmp_buf, sectors * part->info.blksz);
> > @@ -302,7 +302,7 @@ static unsigned long mmc_read_and_flush(struct mmc_part *part,
> >       return blks;
> >  }
> >
> > -static unsigned long mmc_write(struct mmc_part *part, lbaint_t start,
> > +static unsigned long blk_write(struct avb_part *part, lbaint_t start,
> >                              lbaint_t sectors, void *buffer)
> >  {
> >       void *tmp_buf;
> > @@ -330,69 +330,59 @@ static unsigned long mmc_write(struct mmc_part *part, lbaint_t start,
> >               tmp_buf = buffer;
> >       }
> >
> > -     return blk_dwrite(part->mmc_blk,
> > +     return blk_dwrite(part->blk,
> >                         start, sectors, tmp_buf);
> >  }
> >
> > -static struct mmc_part *get_partition(AvbOps *ops, const char *partition)
> > +static struct avb_part *get_partition(AvbOps *ops, const char *partition)
> >  {
> > -     int ret;
> > -     u8 dev_num;
> > -     int part_num = 0;
> > -     struct mmc_part *part;
> > -     struct blk_desc *mmc_blk;
> > +     struct avb_part *part;
> > +     struct AvbOpsData *data;
> > +     size_t dev_part_str_len;
> > +     char *dev_part_str;
> >
> > -     part = malloc(sizeof(struct mmc_part));
> > +     part = malloc(sizeof(struct avb_part));
> >       if (!part)
> >               return NULL;
> >
> > -     dev_num = get_boot_device(ops);
> > -     part->mmc = find_mmc_device(dev_num);
> > -     if (!part->mmc) {
> > -             printf("No MMC device at slot %x\n", dev_num);
> > -             goto err;
> > -     }
> > -
> > -     if (mmc_init(part->mmc)) {
> > -             printf("MMC initialization failed\n");
> > -             goto err;
> > -     }
> > +     if (!ops)
> > +             return NULL;
> >
> > -     ret = mmc_switch_part(part->mmc, part_num);
> > -     if (ret)
> > -             goto err;
> > +     data = ops->user_data;
> > +     if (!data)
> > +             return NULL;
> >
> > -     mmc_blk = mmc_get_blk_desc(part->mmc);
> > -     if (!mmc_blk) {
> > -             printf("Error - failed to obtain block descriptor\n");
> > -             goto err;
> > +     // format is "<devnum>#<partition>\0"
> > +     dev_part_str_len = strlen(data->devnum) + 1 + strlen(partition) + 1;
> > +     dev_part_str = (char *)malloc(dev_part_str_len);
> > +     if (!dev_part_str) {
> > +             free(part);
> > +             return NULL;
> >       }
> >
> > -     ret = part_get_info_by_name(mmc_blk, partition, &part->info);
> > -     if (ret < 0) {
> > -             printf("Can't find partition '%s'\n", partition);
> > -             goto err;
> > +     snprintf(dev_part_str, dev_part_str_len, "%s#%s", data->devnum,
> > +              partition);
> > +     if (part_get_info_by_dev_and_name_or_num(data->iface, dev_part_str,
> > +                                              &part->blk, &part->info,
> > +                                              false) < 0) {
> > +             free(part);
> > +             part = NULL;
> >       }
> >
> > -     part->dev_num = dev_num;
> > -     part->mmc_blk = mmc_blk;
> > -
> > +     free(dev_part_str);
> >       return part;
> > -err:
> > -     free(part);
> > -     return NULL;
> >  }
> >
> > -static AvbIOResult mmc_byte_io(AvbOps *ops,
> > +static AvbIOResult blk_byte_io(AvbOps *ops,
> >                              const char *partition,
> >                              s64 offset,
> >                              size_t num_bytes,
> >                              void *buffer,
> >                              size_t *out_num_read,
> > -                            enum mmc_io_type io_type)
> > +                            enum io_type io_type)
> >  {
> >       ulong ret;
> > -     struct mmc_part *part;
> > +     struct avb_part *part;
> >       u64 start_offset, start_sector, sectors, residue;
> >       u8 *tmp_buf;
> >       size_t io_cnt = 0;
> > @@ -425,7 +415,7 @@ static AvbIOResult mmc_byte_io(AvbOps *ops,
> >                       }
> >
> >                       if (io_type == IO_READ) {
> > -                             ret = mmc_read_and_flush(part,
> > +                             ret = blk_read_and_flush(part,
> >                                                        part->info.start +
> >                                                        start_sector,
> >                                                        1, tmp_buf);
> > @@ -442,7 +432,7 @@ static AvbIOResult mmc_byte_io(AvbOps *ops,
> >                               tmp_buf += (start_offset % part->info.blksz);
> >                               memcpy(buffer, (void *)tmp_buf, residue);
> >                       } else {
> > -                             ret = mmc_read_and_flush(part,
> > +                             ret = blk_read_and_flush(part,
> >                                                        part->info.start +
> >                                                        start_sector,
> >                                                        1, tmp_buf);
> > @@ -456,7 +446,7 @@ static AvbIOResult mmc_byte_io(AvbOps *ops,
> >                                       start_offset % part->info.blksz,
> >                                       buffer, residue);
> >
> > -                             ret = mmc_write(part, part->info.start +
> > +                             ret = blk_write(part, part->info.start +
> >                                               start_sector, 1, tmp_buf);
> >                               if (ret != 1) {
> >                                       printf("%s: write error (%ld, %lld)\n",
> > @@ -474,12 +464,12 @@ static AvbIOResult mmc_byte_io(AvbOps *ops,
> >
> >               if (sectors) {
> >                       if (io_type == IO_READ) {
> > -                             ret = mmc_read_and_flush(part,
> > +                             ret = blk_read_and_flush(part,
> >                                                        part->info.start +
> >                                                        start_sector,
> >                                                        sectors, buffer);
> >                       } else {
> > -                             ret = mmc_write(part,
> > +                             ret = blk_write(part,
> >                                               part->info.start +
> >                                               start_sector,
> >                                               sectors, buffer);
> > @@ -535,7 +525,7 @@ static AvbIOResult read_from_partition(AvbOps *ops,
> >                                      void *buffer,
> >                                      size_t *out_num_read)
> >  {
> > -     return mmc_byte_io(ops, partition_name, offset_from_partition,
> > +     return blk_byte_io(ops, partition_name, offset_from_partition,
> >                          num_bytes, buffer, out_num_read, IO_READ);
> >  }
> >
> > @@ -562,7 +552,7 @@ static AvbIOResult write_to_partition(AvbOps *ops,
> >                                     size_t num_bytes,
> >                                     const void *buffer)
> >  {
> > -     return mmc_byte_io(ops, partition_name, offset_from_partition,
> > +     return blk_byte_io(ops, partition_name, offset_from_partition,
> >                          num_bytes, (void *)buffer, NULL, IO_WRITE);
> >  }
> >
> > @@ -803,7 +793,7 @@ static AvbIOResult get_unique_guid_for_partition(AvbOps *ops,
> >                                                char *guid_buf,
> >                                                size_t guid_buf_size)
> >  {
> > -     struct mmc_part *part;
> > +     struct avb_part *part;
> >       size_t uuid_size;
> >
> >       part = get_partition(ops, partition);
> > @@ -837,7 +827,7 @@ static AvbIOResult get_size_of_partition(AvbOps *ops,
> >                                        const char *partition,
> >                                        u64 *out_size_num_bytes)
> >  {
> > -     struct mmc_part *part;
> > +     struct avb_part *part;
> >
> >       if (!out_size_num_bytes)
> >               return AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE;
> > @@ -976,7 +966,7 @@ free_name:
> >   * AVB2.0 AvbOps alloc/initialisation/free
> >   * ============================================================================
> >   */
> > -AvbOps *avb_ops_alloc(int boot_device)
> > +AvbOps *avb_ops_alloc(const char *iface, const char *devnum)
> >  {
> >       struct AvbOpsData *ops_data;
> >
> > @@ -999,7 +989,8 @@ AvbOps *avb_ops_alloc(int boot_device)
> >       ops_data->ops.read_persistent_value = read_persistent_value;
> >  #endif
> >       ops_data->ops.get_size_of_partition = get_size_of_partition;
> > -     ops_data->mmc_dev = boot_device;
> > +     ops_data->iface = avb_strdup(iface);
> > +     ops_data->devnum = avb_strdup(devnum);
> >
> >       return &ops_data->ops;
> >  }
> > @@ -1018,6 +1009,12 @@ void avb_ops_free(AvbOps *ops)
> >               if (ops_data->tee)
> >                       tee_close_session(ops_data->tee, ops_data->session);
> >  #endif
> > +             if (ops_data->iface)
> > +                     avb_free((void*)ops_data->iface);
> > +
> > +             if (ops_data->devnum)
> > +                     avb_free((void*)ops_data->devnum);
> > +
> >               avb_free(ops_data);
> >       }
> >  }
> > diff --git a/include/avb_verify.h b/include/avb_verify.h
> > index 1e787ba666..732839f74b 100644
> > --- a/include/avb_verify.h
> > +++ b/include/avb_verify.h
> > @@ -9,8 +9,9 @@
> >  #define _AVB_VERIFY_H
> >
> >  #include <../lib/libavb/libavb.h>
> > +#include <blk.h>
> >  #include <mapmem.h>
> > -#include <mmc.h>
> > +#include <part.h>
> >
> >  #define AVB_MAX_ARGS                 1024
> >  #define VERITY_TABLE_OPT_RESTART     "restart_on_corruption"
> > @@ -26,7 +27,8 @@ enum avb_boot_state {
> >
> >  struct AvbOpsData {
> >       struct AvbOps ops;
> > -     int mmc_dev;
> > +     const char *iface;
> > +     const char *devnum;
> >       enum avb_boot_state boot_state;
> >  #ifdef CONFIG_OPTEE_TA_AVB
> >       struct udevice *tee;
> > @@ -34,19 +36,17 @@ struct AvbOpsData {
> >  #endif
> >  };
> >
> > -struct mmc_part {
> > -     int dev_num;
> > -     struct mmc *mmc;
> > -     struct blk_desc *mmc_blk;
> > +struct avb_part {
> > +     struct blk_desc *blk;
> >       struct disk_partition info;
> >  };
> >
> > -enum mmc_io_type {
> > +enum io_type {
> >       IO_READ,
> >       IO_WRITE
> >  };
> >
> > -AvbOps *avb_ops_alloc(int boot_device);
> > +AvbOps *avb_ops_alloc(const char *iface, const char *devnum);
> >  void avb_ops_free(AvbOps *ops);
> >
> >  char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state);
> > @@ -60,7 +60,7 @@ char *append_cmd_line(char *cmdline_orig, char *cmdline_new);
> >   * I/O helper inline functions
> >   * ============================================================================
> >   */
> > -static inline uint64_t calc_offset(struct mmc_part *part, int64_t offset)
> > +static inline uint64_t calc_offset(struct avb_part *part, int64_t offset)
> >  {
> >       u64 part_size = part->info.size * part->info.blksz;
> >
> > @@ -85,17 +85,4 @@ static inline bool is_buf_unaligned(void *buffer)
> >       return (bool)((uintptr_t)buffer % ALLOWED_BUF_ALIGN);
> >  }
> >
> > -static inline int get_boot_device(AvbOps *ops)
> > -{
> > -     struct AvbOpsData *data;
> > -
> > -     if (ops) {
> > -             data = ops->user_data;
> > -             if (data)
> > -                     return data->mmc_dev;
> > -     }
> > -
> > -     return -1;
> > -}
> > -
> >  #endif /* _AVB_VERIFY_H */
> > --
> > 2.30.2


More information about the U-Boot mailing list