[5/8] avb2.0: add boot states and dm-verity support

Message ID 1524662285-19617-6-git-send-email-igor.opaniuk@linaro.org
State New
Headers show
Series
  • Initial integration of AVB2.0
Related show

Commit Message

Igor Opaniuk April 25, 2018, 1:18 p.m.
1. Add initial support of boot states mode (red, green, yellow)
2. Add functions for enforcing dm-verity configurations

Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
---
 cmd/avb.c            |  17 ++++++-
 common/avb_verify.c  | 140 +++++++++++++++++++++++++++++++++++++++++++++++++--
 include/avb_verify.h |  19 ++++++-
 3 files changed, 171 insertions(+), 5 deletions(-)

Comments

Sam Protsenko May 2, 2018, 6:59 p.m. | #1
On 25 April 2018 at 16:18, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
> 1. Add initial support of boot states mode (red, green, yellow)
> 2. Add functions for enforcing dm-verity configurations
>
> Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
> ---
>  cmd/avb.c            |  17 ++++++-
>  common/avb_verify.c  | 140 +++++++++++++++++++++++++++++++++++++++++++++++++--
>  include/avb_verify.h |  19 ++++++-
>  3 files changed, 171 insertions(+), 5 deletions(-)
>
> diff --git a/cmd/avb.c b/cmd/avb.c
> index d040906..2c15b47 100644
> --- a/cmd/avb.c
> +++ b/cmd/avb.c
> @@ -218,6 +218,8 @@ int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
>  {
>         AvbSlotVerifyResult slot_result;
>         AvbSlotVerifyData *out_data;
> +       char *cmdline;
> +       char *extra_args;
>
>         bool unlocked = false;
>         int res = CMD_RET_FAILURE;
> @@ -243,10 +245,23 @@ int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
>                                       "", unlocked, &out_data);
>         switch (slot_result) {
>         case AVB_SLOT_VERIFY_RESULT_OK:
> +               /* Until we don't have support of changing unlock states, we
> +                * assume that we are by default in locked state.
> +                * So in this case we can boot only when verification is
> +                * successful; we also supply in cmdline GREEN boot state
> +                */
>                 printf("Verification passed successfully\n");
>
>                 /* export additional bootargs to AVB_BOOTARGS env var */
> -               env_set(AVB_BOOTARGS, out_data->cmdline);
> +
> +               extra_args = avb_set_state(avb_ops, AVB_GREEN);
> +               if (extra_args)
> +                       cmdline = append_cmd_line(out_data->cmdline,
> +                                                 extra_args);
> +               else
> +                       cmdline = out_data->cmdline;
> +
> +               env_set(AVB_BOOTARGS, cmdline);
>
>                 res = CMD_RET_SUCCESS;
>                 break;
> diff --git a/common/avb_verify.c b/common/avb_verify.c
> index b3d1229..df5e407 100644
> --- a/common/avb_verify.c
> +++ b/common/avb_verify.c
> @@ -119,6 +119,140 @@ const unsigned char avb_root_pub[1032] = {
>
>  /**
>   * ============================================================================
> + * Boot states support (GREEN, YELLOW, ORANGE, RED) and dm_verity
> + * ============================================================================
> + */
> +char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state)
> +{
> +       struct AvbOpsData *data;
> +       char *cmdline = NULL;
> +
> +       if (!ops)
> +               return NULL;
> +
> +       data = (struct AvbOpsData *)ops->user_data;
> +       if (!data)
> +               return NULL;
> +
> +       data->boot_state = boot_state;
> +       switch (boot_state) {
> +       case AVB_GREEN:
> +               cmdline = "androidboot.verifiedbootstate=green";
> +               break;
> +       case AVB_YELLOW:
> +               cmdline = "androidboot.verifiedbootstate=yellow";
> +               break;
> +       case AVB_ORANGE:
> +               cmdline = "androidboot.verifiedbootstate=orange";
> +       case AVB_RED:
> +               break;
> +       }
> +
> +       return cmdline;
> +}
> +
> +char *append_cmd_line(char *cmdline_orig, char *cmdline_new)
> +{
> +       char *cmd_line;
> +
> +       if (!cmdline_new)
> +               return cmdline_orig;
> +
> +       if (cmdline_orig)
> +               cmd_line = cmdline_orig;
> +       else
> +               cmd_line = " ";
> +
> +       cmd_line = avb_strdupv(cmd_line, " ", cmdline_new, NULL);
> +
> +       return cmd_line;
> +}
> +
> +static int avb_find_dm_args(char **args, char *str)
> +{
> +       int i = 0;
> +
> +       if (!str)
> +               return -1;
> +
> +       do {
> +               if ((!args[i]) || (i >= AVB_MAX_ARGS))

Conditions probably should be swapped, to avoid "index out of bounds" error.

> +                       return -1;
> +
> +               if (strstr(args[i], str))
> +                       return i;
> +
> +               i++;
> +       } while (1);
> +}

Just a suggestion: wouldn't it be better to use "for" instead of
"do/while" here? Like this:

       for (i = 0; i < AVB_MAX_ARGS, args[i]; ++i) {
               if (strstr(args[i], str))
                       return i;
       }

       return -1;

> +
> +static char *avb_set_enforce_option(const char *cmdline, const char *option)
> +{
> +       char *cmdarg[AVB_MAX_ARGS];
> +       char *newargs = NULL;
> +       int i = 0;
> +       int total_args;
> +
> +       memset(cmdarg, 0, sizeof(cmdarg));
> +       cmdarg[i++] = strtok((char *)cmdline, " ");
> +
> +       do {
> +               cmdarg[i] = strtok(NULL, " ");
> +               if (!cmdarg[i])
> +                       break;
> +
> +               if (++i >= AVB_MAX_ARGS) {
> +                       printf("%s: Can't handle more then %d args\n",
> +                              __func__, i);
> +                       return NULL;
> +               }
> +       } while (true);
> +
> +       total_args = i;
> +       i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_LOGGING);
> +       if (i >= 0) {
> +               cmdarg[i] = (char *)option;
> +       } else {
> +               i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_RESTART);
> +               if (i < 0) {
> +                       printf("%s: No verity options found\n", __func__);
> +                       return NULL;
> +               }
> +
> +               cmdarg[i] = (char *)option;
> +       }
> +
> +       for (i = 0; i <= total_args; i++)
> +               newargs = append_cmd_line(newargs, cmdarg[i]);
> +
> +       return newargs;
> +}
> +
> +char *avb_set_ignore_corruption(const char *cmdline)
> +{
> +       char *newargs = NULL;
> +
> +       newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_LOGGING);
> +       if (newargs)
> +               newargs = append_cmd_line(newargs,
> +                                         "androidboot.veritymode=eio");
> +
> +       return newargs;
> +}
> +
> +char *avb_set_enforce_verity(const char *cmdline)
> +{
> +       char *newargs;
> +
> +       newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_RESTART);
> +       if (newargs)
> +               newargs = append_cmd_line(newargs,
> +                                         "androidboot.veritymode=enforcing");
> +       return newargs;
> +}
> +
> +/**
> + * ============================================================================
>   * IO(mmc) auxiliary functions
>   * ============================================================================
>   */
> @@ -478,7 +612,7 @@ static AvbIOResult read_rollback_index(AvbOps *ops,
>                                        u64 *out_rollback_index)
>  {
>         /* For now we always return 0 as the stored rollback index. */
> -       printf("TODO: implement %s.\n", __func__);
> +       printf("%s not supported yet\n", __func__);
>
>         if (out_rollback_index)
>                 *out_rollback_index = 0;
> @@ -502,7 +636,7 @@ static AvbIOResult write_rollback_index(AvbOps *ops,
>                                         u64 rollback_index)
>  {
>         /* For now this is a no-op. */
> -       printf("TODO: implement %s.\n", __func__);
> +       printf("%s not supported yet\n", __func__);
>
>         return AVB_IO_RESULT_OK;
>  }
> @@ -522,7 +656,7 @@ static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
>  {
>         /* For now we always return that the device is unlocked. */
>
> -       printf("TODO: implement %s.\n", __func__);
> +       printf("%s not supported yet\n", __func__);
>
>         *out_is_unlocked = true;
>
> diff --git a/include/avb_verify.h b/include/avb_verify.h
> index fb7ab23..9363ca5 100644
> --- a/include/avb_verify.h
> +++ b/include/avb_verify.h
> @@ -11,12 +11,23 @@
>  #include <avb/libavb_ab.h>
>  #include <mmc.h>
>
> -#define ALLOWED_BUF_ALIGN      8
> +#define AVB_MAX_ARGS                   1024
> +#define VERITY_TABLE_OPT_RESTART       "restart_on_corruption"
> +#define VERITY_TABLE_OPT_LOGGING       "ignore_corruption"
> +#define ALLOWED_BUF_ALIGN              8
> +
> +enum avb_boot_state {
> +       AVB_GREEN,
> +       AVB_YELLOW,
> +       AVB_ORANGE,
> +       AVB_RED,
> +};
>
>  struct AvbOpsData {
>         struct AvbOps ops;
>         struct AvbABOps ab_ops;
>         int mmc_dev;
> +       enum avb_boot_state boot_state;
>  };
>
>  struct mmc_part {
> @@ -34,6 +45,12 @@ enum mmc_io_type {
>  AvbOps *avb_ops_alloc(int boot_device);
>  void avb_ops_free(AvbOps *ops);
>
> +char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state);
> +char *avb_set_enforce_verity(const char *cmdline);
> +char *avb_set_ignore_corruption(const char *cmdline);
> +
> +char *append_cmd_line(char *cmdline_orig, char *cmdline_new);
> +
>  /**
>   * ============================================================================
>   * I/O helper inline functions
> --
> 2.7.4
>

Patch

diff --git a/cmd/avb.c b/cmd/avb.c
index d040906..2c15b47 100644
--- a/cmd/avb.c
+++ b/cmd/avb.c
@@ -218,6 +218,8 @@  int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
 {
 	AvbSlotVerifyResult slot_result;
 	AvbSlotVerifyData *out_data;
+	char *cmdline;
+	char *extra_args;
 
 	bool unlocked = false;
 	int res = CMD_RET_FAILURE;
@@ -243,10 +245,23 @@  int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
 				      "", unlocked, &out_data);
 	switch (slot_result) {
 	case AVB_SLOT_VERIFY_RESULT_OK:
+		/* Until we don't have support of changing unlock states, we
+		 * assume that we are by default in locked state.
+		 * So in this case we can boot only when verification is
+		 * successful; we also supply in cmdline GREEN boot state
+		 */
 		printf("Verification passed successfully\n");
 
 		/* export additional bootargs to AVB_BOOTARGS env var */
-		env_set(AVB_BOOTARGS, out_data->cmdline);
+
+		extra_args = avb_set_state(avb_ops, AVB_GREEN);
+		if (extra_args)
+			cmdline = append_cmd_line(out_data->cmdline,
+						  extra_args);
+		else
+			cmdline = out_data->cmdline;
+
+		env_set(AVB_BOOTARGS, cmdline);
 
 		res = CMD_RET_SUCCESS;
 		break;
diff --git a/common/avb_verify.c b/common/avb_verify.c
index b3d1229..df5e407 100644
--- a/common/avb_verify.c
+++ b/common/avb_verify.c
@@ -119,6 +119,140 @@  const unsigned char avb_root_pub[1032] = {
 
 /**
  * ============================================================================
+ * Boot states support (GREEN, YELLOW, ORANGE, RED) and dm_verity
+ * ============================================================================
+ */
+char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state)
+{
+	struct AvbOpsData *data;
+	char *cmdline = NULL;
+
+	if (!ops)
+		return NULL;
+
+	data = (struct AvbOpsData *)ops->user_data;
+	if (!data)
+		return NULL;
+
+	data->boot_state = boot_state;
+	switch (boot_state) {
+	case AVB_GREEN:
+		cmdline = "androidboot.verifiedbootstate=green";
+		break;
+	case AVB_YELLOW:
+		cmdline = "androidboot.verifiedbootstate=yellow";
+		break;
+	case AVB_ORANGE:
+		cmdline = "androidboot.verifiedbootstate=orange";
+	case AVB_RED:
+		break;
+	}
+
+	return cmdline;
+}
+
+char *append_cmd_line(char *cmdline_orig, char *cmdline_new)
+{
+	char *cmd_line;
+
+	if (!cmdline_new)
+		return cmdline_orig;
+
+	if (cmdline_orig)
+		cmd_line = cmdline_orig;
+	else
+		cmd_line = " ";
+
+	cmd_line = avb_strdupv(cmd_line, " ", cmdline_new, NULL);
+
+	return cmd_line;
+}
+
+static int avb_find_dm_args(char **args, char *str)
+{
+	int i = 0;
+
+	if (!str)
+		return -1;
+
+	do {
+		if ((!args[i]) || (i >= AVB_MAX_ARGS))
+			return -1;
+
+		if (strstr(args[i], str))
+			return i;
+
+		i++;
+	} while (1);
+}
+
+static char *avb_set_enforce_option(const char *cmdline, const char *option)
+{
+	char *cmdarg[AVB_MAX_ARGS];
+	char *newargs = NULL;
+	int i = 0;
+	int total_args;
+
+	memset(cmdarg, 0, sizeof(cmdarg));
+	cmdarg[i++] = strtok((char *)cmdline, " ");
+
+	do {
+		cmdarg[i] = strtok(NULL, " ");
+		if (!cmdarg[i])
+			break;
+
+		if (++i >= AVB_MAX_ARGS) {
+			printf("%s: Can't handle more then %d args\n",
+			       __func__, i);
+			return NULL;
+		}
+	} while (true);
+
+	total_args = i;
+	i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_LOGGING);
+	if (i >= 0) {
+		cmdarg[i] = (char *)option;
+	} else {
+		i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_RESTART);
+		if (i < 0) {
+			printf("%s: No verity options found\n", __func__);
+			return NULL;
+		}
+
+		cmdarg[i] = (char *)option;
+	}
+
+	for (i = 0; i <= total_args; i++)
+		newargs = append_cmd_line(newargs, cmdarg[i]);
+
+	return newargs;
+}
+
+char *avb_set_ignore_corruption(const char *cmdline)
+{
+	char *newargs = NULL;
+
+	newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_LOGGING);
+	if (newargs)
+		newargs = append_cmd_line(newargs,
+					  "androidboot.veritymode=eio");
+
+	return newargs;
+}
+
+char *avb_set_enforce_verity(const char *cmdline)
+{
+	char *newargs;
+
+	newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_RESTART);
+	if (newargs)
+		newargs = append_cmd_line(newargs,
+					  "androidboot.veritymode=enforcing");
+	return newargs;
+}
+
+/**
+ * ============================================================================
  * IO(mmc) auxiliary functions
  * ============================================================================
  */
@@ -478,7 +612,7 @@  static AvbIOResult read_rollback_index(AvbOps *ops,
 				       u64 *out_rollback_index)
 {
 	/* For now we always return 0 as the stored rollback index. */
-	printf("TODO: implement %s.\n", __func__);
+	printf("%s not supported yet\n", __func__);
 
 	if (out_rollback_index)
 		*out_rollback_index = 0;
@@ -502,7 +636,7 @@  static AvbIOResult write_rollback_index(AvbOps *ops,
 					u64 rollback_index)
 {
 	/* For now this is a no-op. */
-	printf("TODO: implement %s.\n", __func__);
+	printf("%s not supported yet\n", __func__);
 
 	return AVB_IO_RESULT_OK;
 }
@@ -522,7 +656,7 @@  static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
 {
 	/* For now we always return that the device is unlocked. */
 
-	printf("TODO: implement %s.\n", __func__);
+	printf("%s not supported yet\n", __func__);
 
 	*out_is_unlocked = true;
 
diff --git a/include/avb_verify.h b/include/avb_verify.h
index fb7ab23..9363ca5 100644
--- a/include/avb_verify.h
+++ b/include/avb_verify.h
@@ -11,12 +11,23 @@ 
 #include <avb/libavb_ab.h>
 #include <mmc.h>
 
-#define ALLOWED_BUF_ALIGN	8
+#define AVB_MAX_ARGS			1024
+#define VERITY_TABLE_OPT_RESTART	"restart_on_corruption"
+#define VERITY_TABLE_OPT_LOGGING	"ignore_corruption"
+#define ALLOWED_BUF_ALIGN		8
+
+enum avb_boot_state {
+	AVB_GREEN,
+	AVB_YELLOW,
+	AVB_ORANGE,
+	AVB_RED,
+};
 
 struct AvbOpsData {
 	struct AvbOps ops;
 	struct AvbABOps ab_ops;
 	int mmc_dev;
+	enum avb_boot_state boot_state;
 };
 
 struct mmc_part {
@@ -34,6 +45,12 @@  enum mmc_io_type {
 AvbOps *avb_ops_alloc(int boot_device);
 void avb_ops_free(AvbOps *ops);
 
+char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state);
+char *avb_set_enforce_verity(const char *cmdline);
+char *avb_set_ignore_corruption(const char *cmdline);
+
+char *append_cmd_line(char *cmdline_orig, char *cmdline_new);
+
 /**
  * ============================================================================
  * I/O helper inline functions