diff --git a/src/adb.c b/src/adb.c index b5a820c..69b58fb 100644 --- a/src/adb.c +++ b/src/adb.c @@ -54,6 +54,7 @@ int adb_free(struct adb *db) free(bucket); free(db->adb.ptr); } + memset(db, 0, sizeof *db); return 0; } @@ -67,7 +68,7 @@ void adb_reset(struct adb *db) free(bucket); list_init(&db->bucket[i]); } - db->adb.len = 0; + db->adb.len = sizeof(struct adb_hdr); } static int __adb_dummy_cb(struct adb *db, struct adb_block *b, struct apk_istream *is) @@ -94,6 +95,14 @@ 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); + if (b.len < 16) { + r = -APKE_ADB_BLOCK; + break; + } + if (((struct adb_hdr*)b.ptr)->adb_compat_ver != 0) { + r = -APKE_ADB_VERSION; + break; + } db->adb = b; break; case ADB_BLOCK_SIG: @@ -195,7 +204,15 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec allowed = BIT(ADB_BLOCK_SIG) | BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX); db->adb.ptr = malloc(sz); db->adb.len = adb_block_length(&blk); + if (db->adb.len < 16) { + r = -APKE_ADB_BLOCK; + break; + } if ((r = apk_istream_read(is, db->adb.ptr, sz)) < 0) goto err; + if (((struct adb_hdr*)db->adb.ptr)->adb_compat_ver != 0) { + r = -APKE_ADB_VERSION; + break; + } r = cb(db, &blk, apk_istream_from_blob(&seg.is, db->adb)); if (r < 0) goto err; continue; @@ -252,8 +269,40 @@ int adb_m_process(struct adb *db, struct apk_istream *is, uint32_t expected_sche return __adb_m_stream(db, is, expected_schema, t, cb); } +static size_t adb_w_raw(struct adb *db, struct iovec *vec, size_t n, size_t len, size_t alignment) +{ + void *ptr; + size_t offs, i; + + if ((i = ROUND_UP(db->adb.len, alignment) - db->adb.len) != 0) { + memset(&db->adb.ptr[db->adb.len], 0, i); + db->adb.len += i; + } + + if (db->adb.len + len > db->alloc_len) { + assert(db->num_buckets); + if (!db->alloc_len) db->alloc_len = 8192; + while (db->adb.len + len > db->alloc_len) + db->alloc_len *= 2; + ptr = realloc(db->adb.ptr, db->alloc_len); + assert(ptr); + db->adb.ptr = ptr; + } + + offs = db->adb.len; + for (i = 0; i < n; i++) { + memcpy(&db->adb.ptr[db->adb.len], vec[i].iov_base, vec[i].iov_len); + db->adb.len += vec[i].iov_len; + } + + return offs; +} + + int adb_w_init_dynamic(struct adb *db, uint32_t schema, void *buckets, size_t num_buckets) { + struct adb_hdr hdr = { .adb_compat_ver = 0, .adb_ver = 0 }; + struct iovec vec = { .iov_base = &hdr, .iov_len = sizeof hdr }; size_t i; *db = (struct adb) { @@ -267,6 +316,7 @@ int adb_w_init_dynamic(struct adb *db, uint32_t schema, void *buckets, size_t nu list_init(&db->bucket[i]); } + adb_w_raw(db, &vec, 1, vec.iov_len, sizeof hdr); return 0; } @@ -289,8 +339,8 @@ static inline void *adb_r_deref(const struct adb *db, adb_val_t v, size_t offs, adb_val_t adb_r_root(const struct adb *db) { - if (db->adb.len < sizeof(adb_val_t)) return ADB_NULL; - return *(adb_val_t *)(db->adb.ptr + db->adb.len - sizeof(adb_val_t)); + if (db->adb.len < sizeof(struct adb_hdr)) return ADB_NULL; + return ((struct adb_hdr*)db->adb.ptr)->root; } uint32_t adb_r_int(const struct adb *db, adb_val_t v) @@ -518,35 +568,6 @@ static adb_val_t adb_w_error(struct adb *db, int rc) return ADB_ERROR(rc); } -static size_t adb_w_raw(struct adb *db, struct iovec *vec, size_t n, size_t len, size_t alignment) -{ - void *ptr; - size_t offs, i; - - if ((i = ROUND_UP(db->adb.len, alignment) - db->adb.len) != 0) { - memset(&db->adb.ptr[db->adb.len], 0, i); - db->adb.len += i; - } - - if (db->adb.len + len > db->alloc_len) { - assert(db->num_buckets); - if (!db->alloc_len) db->alloc_len = 8192; - while (db->adb.len + len > db->alloc_len) - db->alloc_len *= 2; - ptr = realloc(db->adb.ptr, db->alloc_len); - assert(ptr); - db->adb.ptr = ptr; - } - - offs = db->adb.len; - for (i = 0; i < n; i++) { - memcpy(&db->adb.ptr[db->adb.len], vec[i].iov_base, vec[i].iov_len); - db->adb.len += vec[i].iov_len; - } - - return offs; -} - static size_t adb_w_data(struct adb *db, struct iovec *vec, size_t nvec, size_t alignment) { size_t len, i; @@ -593,10 +614,11 @@ static size_t adb_w_data1(struct adb *db, void *ptr, size_t len, size_t alignmen void adb_w_root(struct adb *db, adb_val_t root_val) { - struct iovec vec = { - .iov_base = &root_val, .iov_len = sizeof(adb_val_t), - }; - adb_w_raw(db, &vec, 1, vec.iov_len, sizeof root_val); + if (db->adb.len < sizeof(struct adb_hdr)) { + adb_w_error(db, APKE_ADB_HEADER); + return; + } + ((struct adb_hdr*)db->adb.ptr)->root = root_val; } void adb_w_rootobj(struct adb_obj *obj) @@ -697,7 +719,7 @@ adb_val_t adb_w_adb(struct adb *db, struct adb *valdb) { .iov_base = valdb->adb.ptr, .iov_len = valdb->adb.len }, { .iov_base = padding_zeroes, .iov_len = adb_block_padding(&blk) }, }; - if (valdb->adb.len <= 4) return ADB_NULL; + if (valdb->adb.len <= sizeof(struct adb_hdr)) return ADB_NULL; bsz = htole32(iovec_len(vec, ARRAY_SIZE(vec)) - sizeof bsz); return ADB_VAL(ADB_TYPE_BLOB_32, adb_w_raw(db, vec, ARRAY_SIZE(vec), iovec_len(vec, ARRAY_SIZE(vec)), sizeof(uint32_t))); } diff --git a/src/adb.h b/src/adb.h index 6929ea8..e97068a 100644 --- a/src/adb.h +++ b/src/adb.h @@ -77,6 +77,13 @@ static inline apk_blob_t adb_block_blob(struct adb_block *b) { #define ADB_MAX_SIGNATURE_LEN 2048 +struct adb_hdr { + uint8_t adb_compat_ver; + uint8_t adb_ver; + uint16_t reserved; + adb_val_t root; +}; + struct adb_sign_hdr { uint8_t sign_ver, hash_alg; }; diff --git a/src/adb_walk_adb.c b/src/adb_walk_adb.c index 0520ac8..9a74e7e 100644 --- a/src/adb_walk_adb.c +++ b/src/adb_walk_adb.c @@ -111,6 +111,7 @@ static int adb_walk_block(struct adb *db, struct adb_block *b, struct apk_istrea struct adb_walk_ctx *ctx = container_of(db, struct adb_walk_ctx, db); struct adb_walk *d = ctx->d; char tmp[16+ADB_MAX_SIGNATURE_LEN*2]; + struct adb_hdr *hdr; struct adb_sign_hdr *s; uint32_t schema_magic = ctx->db.schema; const struct adb_db_schema *ds; @@ -123,9 +124,12 @@ static int adb_walk_block(struct adb *db, struct adb_block *b, struct apk_istrea d->ops->schema(d, db->schema); for (ds = d->schemas; ds->magic; ds++) if (ds->magic == schema_magic) break; - len = snprintf(tmp, sizeof tmp, "ADB block, size: %zu", sz); + hdr = apk_istream_peek(is, sizeof *hdr); + if (IS_ERR(hdr)) return PTR_ERR(hdr); + len = snprintf(tmp, sizeof tmp, "ADB block, size: %zu, compat: %d, ver: %d", + sz, hdr->adb_compat_ver, hdr->adb_ver); d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len)); - if (ds->root) dump_object(ctx, ds->root, adb_r_root(db)); + if (ds->root && hdr->adb_compat_ver == 0) dump_object(ctx, ds->root, adb_r_root(db)); break; case ADB_BLOCK_SIG: s = (struct adb_sign_hdr*) apk_istream_get(is, sz); diff --git a/src/apk_defines.h b/src/apk_defines.h index fbf66b9..8470835 100644 --- a/src/apk_defines.h +++ b/src/apk_defines.h @@ -45,6 +45,7 @@ enum { APKE_SIGNATURE_INVALID, APKE_ADB_COMPRESSION, APKE_ADB_HEADER, + APKE_ADB_VERSION, APKE_ADB_SCHEMA, APKE_ADB_BLOCK, APKE_ADB_SIGNATURE, diff --git a/src/print.c b/src/print.c index 1662e3d..558527e 100644 --- a/src/print.c +++ b/src/print.c @@ -41,6 +41,7 @@ const char *apk_error_str(int error) case APKE_SIGNATURE_INVALID: return "BAD signature"; case APKE_ADB_COMPRESSION: return "ADB compression not supported"; case APKE_ADB_HEADER: return "ADB header error"; + case APKE_ADB_VERSION: return "incompatible ADB version"; case APKE_ADB_SCHEMA: return "ADB schema error"; case APKE_ADB_BLOCK: return "ADB block error"; case APKE_ADB_SIGNATURE: return "ADB signature block error";