Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 75 additions & 1 deletion native/src/boot/bootimg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1019,10 +1019,84 @@ void repack(Utf8CStr src_img, Utf8CStr out_img, bool skip_comp) {
memcpy(footer, boot.avb_footer, sizeof(AvbFooter));
footer->original_image_size = __builtin_bswap64(aosp_img_size);
footer->vbmeta_offset = __builtin_bswap64(off.vbmeta);

auto vbmeta = reinterpret_cast<AvbVBMetaImageHeader*>(out.data() + off.vbmeta);

if (check_env("PATCHVBMETAFLAG")) {
auto vbmeta = reinterpret_cast<AvbVBMetaImageHeader*>(out.data() + off.vbmeta);
vbmeta->flags = __builtin_bswap32(3);
}

// Patch hash descriptor
for (auto &desc : vbmeta->descriptors()) {
if (__builtin_bswap64(desc.tag) != AVB_DESCRIPTOR_TAG_HASH)
continue;

// enforce size limits; protect against adversarial input.
size_t buf_remaining = out.data() + out.size() - reinterpret_cast<uint8_t *>(&desc);
if (buf_remaining < __builtin_bswap64(desc.num_bytes_following) || buf_remaining - __builtin_bswap64(desc.num_bytes_following) < sizeof(AvbDescriptor)) {
// beware: both conditions are necessary because underflow in the subtraction could wrap
fprintf(stderr, "AVB hash descriptor num_bytes_following overflows buffer\n");
break;
}

if (__builtin_bswap64(desc.num_bytes_following) < sizeof(AvbHashDescriptor) - sizeof(AvbDescriptor)) {
fprintf(stderr, "AvbDescriptor too small to hold AvbHashDescriptor\n");
break;
}

auto &hd = reinterpret_cast<AvbHashDescriptor &>(desc);

// Update image_size
hd.image_size = __builtin_bswap64(aosp_img_size);

// Recompute hash
auto *algo = reinterpret_cast<char *>(hd.hash_algorithm);
bool is_sha1 = memcmp(hd.hash_algorithm, "sha1", 5) == 0;
bool is_sha256 = memcmp(hd.hash_algorithm, "sha256", 7) == 0;

uint32_t name_len = __builtin_bswap32(hd.partition_name_len);
uint32_t salt_len = __builtin_bswap32(hd.salt_len);
uint32_t digest_len = __builtin_bswap32(hd.digest_len);

// Get pointers to the (flexibly sized) payloads, checking each against desc_end
uint8_t *desc_end = reinterpret_cast<uint8_t *>(&desc) + sizeof(AvbDescriptor) + __builtin_bswap64(desc.num_bytes);

uint8_t *name = reinterpret_cast<uint8_t *>(&hd + 1);
if (name > desc_end) {
fprintf(stderr, "AVB hash descriptor overflows bounds\n");
break;
}
if ((size_t)(desc_end - name) < name_len) {
fprintf(stderr, "AVB hash descriptor name of %u bytes overflows bounds\n", name_len);
break;
}

uint8_t *salt = name + name_len;
if ((size_t)(desc_end - salt) < salt_len) {
fprintf(stderr, "AVB hash descriptor salt of %u bytes overflows bounds\n", salt_len);
break;
}

uint8_t *digest = salt + salt_len;
if ((size_t)(desc_end - digest) < digest_len) {
fprintf(stderr, "AVB hash descriptor digest of %u bytes overflows bounds\n", digest_len);
break;
}

if (is_sha1 || is_sha256) {
digest_len = is_sha1 ? 20 : 32;
hd.digest_len = __builtin_bswap32(digest_len);

auto ctx = get_sha(is_sha1);
ctx->update(byte_view(salt, salt_len));
ctx->update(byte_view(out.data(), aosp_img_size));
ctx->finalize_into(byte_data(digest, digest_len));
} else {
fprintf(stderr, "Unsupported AVB hash algorithm: %.32s — zeroing digest\n", algo);
memset(digest, 0, desc_end - digest);
}
break;
}
}

if (boot.flags[DHTB_FLAG]) {
Expand Down
68 changes: 68 additions & 0 deletions native/src/boot/bootimg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,34 @@ struct AvbFooter {
uint8_t reserved[28];
} __attribute__((packed));

// https://android.googlesource.com/platform/external/avb/+/refs/heads/android11-release/libavb/avb_descriptor.h
enum AvbDescriptorTag : uint64_t {
AVB_DESCRIPTOR_TAG_PROPERTY = 0,
AVB_DESCRIPTOR_TAG_HASHTREE = 1,
AVB_DESCRIPTOR_TAG_HASH = 2,
AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE = 3,
AVB_DESCRIPTOR_TAG_CHAIN_PARTITION = 4,
};

struct AvbDescriptor {
uint64_t tag;
uint64_t num_bytes_following; // size of descriptor body (excludes this header); should always be a multiple of 8.
} __attribute__((packed));

// https://android.googlesource.com/platform/external/avb/+/refs/heads/android11-release/libavb/avb_hash_descriptor.h
// for AvbDescriptor.tag == AVB_DESCRIPTOR_TAG_HASH
struct AvbHashDescriptor {
AvbDescriptor header;
uint64_t image_size;
uint8_t hash_algorithm[32];
uint32_t partition_name_len;
uint32_t salt_len;
uint32_t digest_len;
uint32_t flags;
uint8_t reserved[60];
// followed by: partition_name, salt, digest (variable length)
} __attribute__((packed));

// https://android.googlesource.com/platform/external/avb/+/refs/heads/android11-release/libavb/avb_vbmeta_image.h
struct AvbVBMetaImageHeader {
uint8_t magic[AVB_MAGIC_LEN];
Expand All @@ -92,8 +120,48 @@ struct AvbVBMetaImageHeader {
uint32_t rollback_index_location;
uint8_t release_string[AVB_RELEASE_STRING_SIZE];
uint8_t reserved[80];

struct AvbDescriptorRange descriptors();
} __attribute__((packed));

struct AvbDescriptorIterator {
AvbDescriptor *ptr;
AvbDescriptor &operator*() const { return *ptr; }
AvbDescriptor *operator->() const { return ptr; }
bool operator!=(const AvbDescriptorIterator &o) const {
if(ptr == nullptr) return false;
return ptr != o.ptr;
}
AvbDescriptorIterator &operator++() {
if (ptr->num_bytes_following % 8 != 0) {
// This is an error, a malformed image.
// https://android.googlesource.com/platform/external/avb/+/refs/heads/android11-release/libavb/avb_descriptor.h#60
// > For padding, |num_bytes_following| is always a multiple of 8.
// we can't signal an error easily, but we can stop the iteration.
ptr = nullptr;
return *this;
}
ptr = reinterpret_cast<AvbDescriptor *>(
reinterpret_cast<uint8_t *>(ptr) + sizeof(AvbDescriptor) + __builtin_bswap64(ptr->num_bytes_following));
return *this;
}
};

struct AvbDescriptorRange {
AvbDescriptor *first, *last;
AvbDescriptorIterator begin() const { return {first}; }
AvbDescriptorIterator end() const { return {last}; }
};

inline AvbDescriptorRange AvbVBMetaImageHeader::descriptors() {
auto *base = reinterpret_cast<const uint8_t *>(this) + sizeof(AvbVBMetaImageHeader);
base += __builtin_bswap64(authentication_data_block_size);
base += __builtin_bswap64(descriptors_offset);
auto *first = reinterpret_cast<AvbDescriptor *>(const_cast<uint8_t *>(base));
auto *last = reinterpret_cast<AvbDescriptor *>(const_cast<uint8_t *>(base) + __builtin_bswap64(descriptors_size));
return {first, last};
}

/*********************
* Boot Image Headers
*********************/
Expand Down