From c5d8d286f6920542a73232d503d92e9a82b7be58 Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Mon, 11 Sep 2023 13:09:58 +0300 Subject: adb: implement ADB_BLOCK_EXT flavor for large files --- src/adb.c | 46 +++++++++++++++++++++------------------------- src/adb.h | 38 +++++++++++++++++++++++++++++--------- src/adb_walk_adb.c | 6 +++--- src/extract_v3.c | 2 +- 4 files changed, 54 insertions(+), 38 deletions(-) diff --git a/src/adb.c b/src/adb.c index 3f22187..4bc89d4 100644 --- a/src/adb.c +++ b/src/adb.c @@ -18,11 +18,13 @@ static char padding_zeroes[ADB_BLOCK_ALIGNMENT] = {0}; /* Block enumeration */ static inline struct adb_block *adb_block_validate(struct adb_block *blk, apk_blob_t b) { - size_t pos = (char *)blk - b.ptr; + size_t pos = (char *)blk - b.ptr, len = (size_t)(b.len - pos); if (pos == b.len) return NULL; - if (sizeof(struct adb_block) > b.len - pos) return ERR_PTR(-APKE_ADB_BLOCK); - if (adb_block_rawsize(blk) < sizeof(struct adb_block)) return ERR_PTR(-APKE_ADB_BLOCK); - if (adb_block_size(blk) > b.len - pos) return ERR_PTR(-APKE_ADB_BLOCK); + if (sizeof(uint32_t) > len) return ERR_PTR(-APKE_ADB_BLOCK); + size_t hdrlen = adb_block_hdrsize(blk); + if (hdrlen > len) return ERR_PTR(-APKE_ADB_BLOCK); + if (adb_block_rawsize(blk) < hdrlen) return ERR_PTR(-APKE_ADB_BLOCK); + if (adb_block_size(blk) > len) return ERR_PTR(-APKE_ADB_BLOCK); return blk; } @@ -94,7 +96,7 @@ static int __adb_m_parse(struct adb *db, apk_blob_t data, struct apk_trust *t, } switch (type) { case ADB_BLOCK_ADB: - allowed = BIT(ADB_BLOCK_SIG) | BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX); + allowed = BIT(ADB_BLOCK_SIG) | BIT(ADB_BLOCK_DATA); if (b.len < 16) { r = -APKE_ADB_BLOCK; goto err; @@ -111,15 +113,12 @@ static int __adb_m_parse(struct adb *db, apk_blob_t data, struct apk_trust *t, trusted = 1; break; case ADB_BLOCK_DATA: - allowed = BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX); + allowed = BIT(ADB_BLOCK_DATA); if (!trusted) { r = -APKE_SIGNATURE_UNTRUSTED; goto err; } break; - case ADB_BLOCK_DATAX: - r = -APKE_ADB_BLOCK; - goto err; } r = cb(db, blk, apk_istream_from_blob(&is, b)); if (r < 0) break; @@ -175,7 +174,6 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec void *sig; int r = 0, trusted = (t && t->allow_untrusted) ? 1 : 0; uint32_t type, allowed = BIT(ADB_BLOCK_ADB); - size_t sz; if (IS_ERR(is)) return PTR_ERR(is); @@ -193,8 +191,11 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec } do { - r = apk_istream_read_max(is, &blk, sizeof blk); - if (r != sizeof blk) break; + size_t hdrsize = sizeof blk; + void *hdrptr = apk_istream_peek(is, sizeof(blk.type_size)); + if (!IS_ERR(hdrptr)) hdrsize = adb_block_hdrsize(hdrptr); + r = apk_istream_read_max(is, &blk, hdrsize); + if (r != hdrsize) break; type = adb_block_type(&blk); if (!(BIT(type) & allowed)) { @@ -202,10 +203,10 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec break; } - sz = adb_block_length(&blk); + uint64_t sz = adb_block_length(&blk); switch (type) { case ADB_BLOCK_ADB: - allowed = BIT(ADB_BLOCK_SIG) | BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX); + allowed = BIT(ADB_BLOCK_SIG) | BIT(ADB_BLOCK_DATA); db->adb.ptr = malloc(sz); db->adb.len = sz; if (db->adb.len < 16) { @@ -231,15 +232,12 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec trusted = 1; break; case ADB_BLOCK_DATA: - allowed = BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX); + allowed = BIT(ADB_BLOCK_DATA); if (!trusted) { r = -APKE_SIGNATURE_UNTRUSTED; goto err; } break; - case ADB_BLOCK_DATAX: - r = -APKE_ADB_BLOCK; - goto err; } apk_istream_segment(&seg, is, sz, 0); @@ -762,7 +760,7 @@ adb_val_t adb_w_adb(struct adb *db, struct adb *valdb) struct adb_block blk = adb_block_init(ADB_BLOCK_ADB, valdb->adb.len); struct iovec vec[] = { { .iov_base = &bsz, .iov_len = sizeof bsz }, - { .iov_base = &blk, .iov_len = sizeof blk }, + { .iov_base = &blk, .iov_len = adb_block_hdrsize(&blk) }, { .iov_base = valdb->adb.ptr, .iov_len = valdb->adb.len }, { .iov_base = padding_zeroes, .iov_len = adb_block_padding(&blk) }, }; @@ -1089,9 +1087,7 @@ int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t val) size_t padding = adb_block_padding(&blk); int r; - if (val.len & ~0x3fffffff) return -APKE_ADB_LIMIT; - - r = apk_ostream_write(os, &blk, sizeof blk); + r = apk_ostream_write(os, &blk, adb_block_hdrsize(&blk)); if (r < 0) return r; r = apk_ostream_write(os, val.ptr, val.len); @@ -1105,7 +1101,7 @@ int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t val) return 0; } -int adb_c_block_data(struct apk_ostream *os, apk_blob_t hdr, uint32_t size, struct apk_istream *is) +int adb_c_block_data(struct apk_ostream *os, apk_blob_t hdr, uint64_t size, struct apk_istream *is) { struct adb_block blk = adb_block_init(ADB_BLOCK_DATA, size + hdr.len); size_t padding = adb_block_padding(&blk); @@ -1114,7 +1110,7 @@ int adb_c_block_data(struct apk_ostream *os, apk_blob_t hdr, uint32_t size, stru if (IS_ERR(os)) return PTR_ERR(os); if (IS_ERR(is)) return apk_ostream_cancel(os, PTR_ERR(is)); - r = apk_ostream_write(os, &blk, sizeof blk); + r = apk_ostream_write(os, &blk, adb_block_hdrsize(&blk)); if (r < 0) return r; r = apk_ostream_write(os, hdr.ptr, hdr.len); @@ -1133,7 +1129,7 @@ int adb_c_block_data(struct apk_ostream *os, apk_blob_t hdr, uint32_t size, stru int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_istream *is, struct adb_verify_ctx *vfy) { - size_t blk_sz = adb_block_length(b); + uint64_t blk_sz = adb_block_length(b); size_t padding = adb_block_padding(b); int r; diff --git a/src/adb.h b/src/adb.h index 8649989..32152ae 100644 --- a/src/adb.h +++ b/src/adb.h @@ -57,21 +57,41 @@ struct adb_file_header { #define ADB_BLOCK_ADB 0 #define ADB_BLOCK_SIG 1 #define ADB_BLOCK_DATA 2 -#define ADB_BLOCK_DATAX 3 +#define ADB_BLOCK_EXT 3 struct adb_block { uint32_t type_size; + uint32_t reserved; + uint64_t x_size; }; -static inline struct adb_block adb_block_init(uint32_t type, uint32_t length) { - return (struct adb_block) { .type_size = htole32((type << 30) + sizeof(struct adb_block) + length)}; +static inline struct adb_block adb_block_init(uint32_t type, uint64_t length) { + if (length <= 0x3fffffff) { + return (struct adb_block) { + .type_size = htole32((type << 30) + sizeof(uint32_t) + length), + }; + } + return (struct adb_block) { + .type_size = htole32((ADB_BLOCK_EXT << 30) + type), + .x_size = htole64(sizeof(struct adb_block) + length), + }; } -static inline uint32_t adb_block_type(struct adb_block *b) { return le32toh((b)->type_size) >> 30; } -static inline uint32_t adb_block_rawsize(struct adb_block *b) { return le32toh((b)->type_size) & 0x3fffffff; } -static inline uint32_t adb_block_size(struct adb_block *b) { return ROUND_UP(adb_block_rawsize(b), ADB_BLOCK_ALIGNMENT); } -static inline uint32_t adb_block_length(struct adb_block *b) { return adb_block_rawsize(b) - sizeof(struct adb_block); } +static inline uint32_t adb_block_is_ext(struct adb_block *b) { + return (le32toh((b)->type_size) >> 30) == ADB_BLOCK_EXT; +} +static inline uint32_t adb_block_type(struct adb_block *b) { + return adb_block_is_ext(b) ? (le32toh(b->type_size) & 0x3fffffff) : (le32toh(b->type_size) >> 30); +} +static inline uint64_t adb_block_rawsize(struct adb_block *b) { + return adb_block_is_ext(b) ? le64toh(b->x_size) : (le32toh(b->type_size) & 0x3fffffff); +} +static inline uint32_t adb_block_hdrsize(struct adb_block *b) { + return adb_block_is_ext(b) ? sizeof *b : sizeof b->type_size; +} +static inline uint64_t adb_block_size(struct adb_block *b) { return ROUND_UP(adb_block_rawsize(b), ADB_BLOCK_ALIGNMENT); } +static inline uint64_t adb_block_length(struct adb_block *b) { return adb_block_rawsize(b) - adb_block_hdrsize(b); } static inline uint32_t adb_block_padding(struct adb_block *b) { return adb_block_size(b) - adb_block_rawsize(b); } -static inline void *adb_block_payload(struct adb_block *b) { return b + 1; } +static inline void *adb_block_payload(struct adb_block *b) { return (char*)b + adb_block_hdrsize(b); } static inline apk_blob_t adb_block_blob(struct adb_block *b) { return APK_BLOB_PTR_LEN(adb_block_payload(b), adb_block_length(b)); } @@ -243,7 +263,7 @@ int adb_s_field_by_name(const struct adb_object_schema *, const char *); /* Creation */ int adb_c_header(struct apk_ostream *os, struct adb *db); int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t); -int adb_c_block_data(struct apk_ostream *os, apk_blob_t hdr, uint32_t size, struct apk_istream *is); +int adb_c_block_data(struct apk_ostream *os, apk_blob_t hdr, uint64_t size, struct apk_istream *is); int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_istream *is, struct adb_verify_ctx *); int adb_c_adb(struct apk_ostream *os, struct adb *db, struct apk_trust *t); int adb_c_create(struct apk_ostream *os, struct adb *db, struct apk_trust *t); diff --git a/src/adb_walk_adb.c b/src/adb_walk_adb.c index 3ceac56..e1a686d 100644 --- a/src/adb_walk_adb.c +++ b/src/adb_walk_adb.c @@ -115,7 +115,7 @@ static int adb_walk_block(struct adb *db, struct adb_block *b, struct apk_istrea struct adb_sign_hdr *s; uint32_t schema_magic = ctx->db.schema; const struct adb_db_schema *ds; - size_t sz = adb_block_length(b); + uint64_t sz = adb_block_length(b); apk_blob_t data, c = APK_BLOB_BUF(tmp); int r; @@ -142,10 +142,10 @@ static int adb_walk_block(struct adb *db, struct adb_block *b, struct apk_istrea apk_blob_push_fmt(&c, ": %s", r ? apk_error_str(r) : "OK"); break; case ADB_BLOCK_DATA: - apk_blob_push_fmt(&c, "data block, size: %zu", sz); + apk_blob_push_fmt(&c, "data block, size: %" PRIu64, sz); break; default: - apk_blob_push_fmt(&c, "unknown block %d, size: %zu", adb_block_type(b), sz); + apk_blob_push_fmt(&c, "unknown block %d, size: %" PRIu64, adb_block_type(b), sz); break; } d->ops->comment(d, apk_blob_pushed(APK_BLOB_BUF(tmp), c)); diff --git a/src/extract_v3.c b/src/extract_v3.c index 2ee31c0..f647867 100644 --- a/src/extract_v3.c +++ b/src/extract_v3.c @@ -182,7 +182,7 @@ static int apk_extract_v3_data_block(struct adb *db, struct adb_block *b, struct struct apk_extract_v3_ctx *ctx = container_of(db, struct apk_extract_v3_ctx, db); struct apk_extract_ctx *ectx = ctx->ectx; struct adb_data_package *hdr; - size_t sz = adb_block_length(b); + uint64_t sz = adb_block_length(b); int r; if (adb_block_type(b) != ADB_BLOCK_DATA) return 0; -- cgit v1.2.3-60-g2f50