boot: android: fix AvbOps and verify-data leaks in AVB path
run_avb_verification() allocates an AvbOps via avb_ops_alloc() but never
frees it on any return path. Every Android boot attempt therefore leaks
the AvbOpsData structure and, when CONFIG_OPTEE_TA_AVB is enabled, leaves
the OP-TEE session open (it is only closed inside avb_ops_free()).
In addition, the AvbSlotVerifyData returned by avb_slot_verify() is only
released on the failure branches. The successful "return 0" paths (both
the locked GREEN/OK case and the unlocked ORANGE/ERROR_VERIFICATION case)
return without freeing it, leaking the whole out_data (cmdline and loaded
partition metadata) on every good boot.
Route all exit paths through a single cleanup label that frees both
out_data and avb_ops.
Fixes: 125d9f3306 ("bootstd: Add a bootmeth for Android")
Signed-off-by: Igor Opaniuk <igor.opaniuk@gmail.com>
Reviewed-by: Mattijs Korpershoek <mkorpershoek@kernel.org>
Link: https://patch.msgid.link/20260712-avb-fix-memory-leaks-v1-1-51d6d5a42631@gmail.com
Signed-off-by: Mattijs Korpershoek <mkorpershoek@kernel.org>
This commit is contained in:
committed by
Mattijs Korpershoek
parent
b605609724
commit
a7f65a6b6a
+21
-16
@@ -428,7 +428,7 @@ static int run_avb_verification(struct bootflow *bflow)
|
||||
const char * const requested_partitions[] = {"boot", "vendor_boot", NULL};
|
||||
struct AvbOps *avb_ops;
|
||||
AvbSlotVerifyResult result;
|
||||
AvbSlotVerifyData *out_data;
|
||||
AvbSlotVerifyData *out_data = NULL;
|
||||
enum avb_boot_state boot_state;
|
||||
char *extra_args;
|
||||
char slot_suffix[3] = "";
|
||||
@@ -443,8 +443,10 @@ static int run_avb_verification(struct bootflow *bflow)
|
||||
sprintf(slot_suffix, "_%s", priv->slot);
|
||||
|
||||
ret = avb_ops->read_is_device_unlocked(avb_ops, &unlocked);
|
||||
if (ret != AVB_IO_RESULT_OK)
|
||||
return log_msg_ret("avb lock", -EIO);
|
||||
if (ret != AVB_IO_RESULT_OK) {
|
||||
ret = log_msg_ret("avb lock", -EIO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = avb_slot_verify(avb_ops,
|
||||
requested_partitions,
|
||||
@@ -458,9 +460,8 @@ static int run_avb_verification(struct bootflow *bflow)
|
||||
if (result != AVB_SLOT_VERIFY_RESULT_OK) {
|
||||
printf("Verification failed, reason: %s\n",
|
||||
str_avb_slot_error(result));
|
||||
if (out_data)
|
||||
avb_slot_verify_data_free(out_data);
|
||||
return log_msg_ret("avb verify", -EIO);
|
||||
ret = log_msg_ret("avb verify", -EIO);
|
||||
goto out;
|
||||
}
|
||||
boot_state = AVB_GREEN;
|
||||
} else {
|
||||
@@ -469,9 +470,8 @@ static int run_avb_verification(struct bootflow *bflow)
|
||||
result != AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION) {
|
||||
printf("Unlocked verification failed, reason: %s\n",
|
||||
str_avb_slot_error(result));
|
||||
if (out_data)
|
||||
avb_slot_verify_data_free(out_data);
|
||||
return log_msg_ret("avb verify unlocked", -EIO);
|
||||
ret = log_msg_ret("avb verify unlocked", -EIO);
|
||||
goto out;
|
||||
}
|
||||
boot_state = AVB_ORANGE;
|
||||
}
|
||||
@@ -480,23 +480,28 @@ static int run_avb_verification(struct bootflow *bflow)
|
||||
if (extra_args) {
|
||||
/* extra_args will be modified after this. This is fine */
|
||||
ret = avb_append_commandline_arg(bflow, extra_args);
|
||||
if (ret < 0)
|
||||
goto free_out_data;
|
||||
if (ret < 0) {
|
||||
ret = log_msg_ret("avb cmdline", ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == AVB_SLOT_VERIFY_RESULT_OK) {
|
||||
ret = avb_append_commandline(bflow, out_data->cmdline);
|
||||
if (ret < 0)
|
||||
goto free_out_data;
|
||||
if (ret < 0) {
|
||||
ret = log_msg_ret("avb cmdline", ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
|
||||
free_out_data:
|
||||
out:
|
||||
if (out_data)
|
||||
avb_slot_verify_data_free(out_data);
|
||||
avb_ops_free(avb_ops);
|
||||
|
||||
return log_msg_ret("avb cmdline", ret);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int run_avb_verification(struct bootflow *bflow)
|
||||
|
||||
Reference in New Issue
Block a user