diff options
Diffstat (limited to 'src/adb.c')
-rw-r--r-- | src/adb.c | 396 |
1 files changed, 264 insertions, 132 deletions
@@ -1,13 +1,10 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <malloc.h> -#include <assert.h> #include <errno.h> #include <sys/mman.h> #include <sys/stat.h> -#include <openssl/pem.h> -#include <openssl/err.h> +#include <sys/uio.h> #include "adb.h" #include "apk_blob.h" @@ -18,11 +15,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; } @@ -37,7 +36,7 @@ static struct adb_block *adb_block_next(struct adb_block *cur, apk_blob_t b) } #define adb_foreach_block(__blk, __adb) \ - for (__blk = adb_block_first(__adb); !IS_ERR_OR_NULL(__blk); __blk = adb_block_next(__blk, __adb)) + for (__blk = adb_block_first(__adb); __blk && !IS_ERR(__blk); __blk = adb_block_next(__blk, __adb)) /* Init stuff */ int adb_free(struct adb *db) @@ -82,7 +81,7 @@ static int __adb_m_parse(struct adb *db, apk_blob_t data, struct apk_trust *t, struct adb_verify_ctx vfy = {}; struct adb_block *blk; struct apk_istream is; - int r = 0, trusted = t ? 0 : 1; + int r = 0, trusted = (t && t->allow_untrusted) ? 1 : 0; uint32_t type, allowed = BIT(ADB_BLOCK_ADB); adb_foreach_block(blk, data) { @@ -94,14 +93,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); + allowed = BIT(ADB_BLOCK_SIG) | BIT(ADB_BLOCK_DATA); if (b.len < 16) { r = -APKE_ADB_BLOCK; - break; + goto err; } if (((struct adb_hdr*)b.ptr)->adb_compat_ver != 0) { r = -APKE_ADB_VERSION; - break; + goto err; } db->adb = b; break; @@ -111,11 +110,11 @@ 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); - if (!trusted) goto err; - break; - case ADB_BLOCK_DATAX: - r = -APKE_ADB_BLOCK; + allowed = BIT(ADB_BLOCK_DATA); + if (!trusted) { + r = -APKE_SIGNATURE_UNTRUSTED; + goto err; + } break; } r = cb(db, blk, apk_istream_from_blob(&is, b)); @@ -170,9 +169,8 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec struct adb_block blk; struct apk_segment_istream seg; void *sig; - int r = 0, trusted = t ? 0 : 1; + 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); @@ -190,32 +188,36 @@ 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)) { r = -APKE_ADB_BLOCK; break; } - sz = adb_block_size(&blk) - sizeof 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 = adb_block_length(&blk); + db->adb.len = sz; if (db->adb.len < 16) { r = -APKE_ADB_BLOCK; - break; + goto err; } 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; + goto err; } r = cb(db, &blk, apk_istream_from_blob(&seg.is, db->adb)); if (r < 0) goto err; - continue; + goto skip_padding; case ADB_BLOCK_SIG: sig = apk_istream_peek(is, sz); if (IS_ERR(sig)) { @@ -223,31 +225,34 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec goto err; } if (!trusted && - adb_trust_verify_signature(t, db, &vfy, APK_BLOB_PTR_LEN(sig, adb_block_length(&blk))) == 0) + adb_trust_verify_signature(t, db, &vfy, APK_BLOB_PTR_LEN(sig, sz)) == 0) trusted = 1; break; case ADB_BLOCK_DATA: - allowed = BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX); - if (!trusted) goto err; - break; - case ADB_BLOCK_DATAX: - r = -APKE_ADB_BLOCK; + allowed = BIT(ADB_BLOCK_DATA); + if (!trusted) { + r = -APKE_SIGNATURE_UNTRUSTED; + goto err; + } break; } apk_istream_segment(&seg, is, sz, 0); r = cb(db, &blk, &seg.is); + r = apk_istream_close_error(&seg.is, r); if (r < 0) break; - r = apk_istream_close(&seg.is); + + skip_padding: + r = apk_istream_read(is, 0, adb_block_padding(&blk)); if (r < 0) break; } while (1); err: if (r > 0) r = -APKE_ADB_BLOCK; - if (r == 0) { + if (r == 0 || r == -ECANCELED) { if (!trusted) r = -APKE_SIGNATURE_UNTRUSTED; else if (!db->adb.ptr) r = -APKE_ADB_BLOCK; } - if (r != 0) { + if (r != 0 && r != -ECANCELED) { free(db->adb.ptr); db->adb = APK_BLOB_NULL; } @@ -346,9 +351,10 @@ adb_val_t adb_r_root(const struct adb *db) return ((struct adb_hdr*)db->adb.ptr)->root; } -uint32_t adb_r_int(const struct adb *db, adb_val_t v) +uint64_t adb_r_int(const struct adb *db, adb_val_t v) { uint32_t *int4; + uint64_t *int8; switch (ADB_VAL_TYPE(v)) { case ADB_TYPE_INT: @@ -357,6 +363,10 @@ uint32_t adb_r_int(const struct adb *db, adb_val_t v) int4 = adb_r_deref(db, v, 0, sizeof int4); if (!int4) return 0; return le32toh(*int4); + case ADB_TYPE_INT_64: + int8 = adb_r_deref(db, v, 0, sizeof int8); + if (!int8) return 0; + return le64toh(*int8); default: return 0; } @@ -437,7 +447,7 @@ adb_val_t adb_ro_val(const struct adb_obj *o, unsigned i) return o->obj[i]; } -uint32_t adb_ro_int(const struct adb_obj *o, unsigned i) +uint64_t adb_ro_int(const struct adb_obj *o, unsigned i) { return adb_r_int(o->db, adb_ro_val(o, i)); } @@ -456,78 +466,88 @@ struct adb_obj *adb_ro_obj(const struct adb_obj *o, unsigned i, struct adb_obj * schema = container_of(o->schema->fields[0].kind, struct adb_object_schema, kind); else if (i > 0 && i < o->schema->num_fields) schema = container_of(o->schema->fields[i-1].kind, struct adb_object_schema, kind); - assert(schema->kind == ADB_KIND_OBJECT || schema->kind == ADB_KIND_ARRAY); + assert(schema && (schema->kind == ADB_KIND_OBJECT || schema->kind == ADB_KIND_ARRAY)); } return adb_r_obj(o->db, adb_ro_val(o, i), no, schema); } -int adb_ro_cmp(const struct adb_obj *o1, const struct adb_obj *o2, unsigned i) +int adb_ro_cmpobj(const struct adb_obj *tmpl, const struct adb_obj *obj, unsigned mode) { - assert(o1->schema->kind == ADB_KIND_OBJECT); - assert(o1->schema == o2->schema); - assert(i > 0 && i < o1->schema->num_fields); + const struct adb_object_schema *schema = obj->schema; + int is_set, r = 0; - switch (*o1->schema->fields[i-1].kind) { - case ADB_KIND_BLOB: - case ADB_KIND_INT: - return container_of(o1->schema->fields[i-1].kind, struct adb_scalar_schema, kind)->compare( - o1->db, adb_ro_val(o1, i), - o2->db, adb_ro_val(o2, i)); - case ADB_KIND_OBJECT: { - struct adb_obj so1, so2; - adb_ro_obj(o1, i, &so1); - adb_ro_obj(o2, i, &so2); - return so1.schema->compare(&so1, &so2); + assert(schema->kind == ADB_KIND_OBJECT); + assert(schema == tmpl->schema); + + for (int i = ADBI_FIRST; i < adb_ro_num(tmpl); i++) { + is_set = adb_ro_val(tmpl, i) != ADB_VAL_NULL; + if (mode == ADB_OBJCMP_EXACT || is_set) { + r = adb_ro_cmp(tmpl, obj, i, mode); + if (r) return r; } + if (mode == ADB_OBJCMP_INDEX && !is_set) + return 0; + if (mode != ADB_OBJCMP_EXACT && i >= schema->num_compare) + return 0; } - assert(0); + return 0; } -static struct adb *__db1, *__db2; -static const struct adb_object_schema *__schema; - -static int wacmp(const void *p1, const void *p2) +int adb_ro_cmp(const struct adb_obj *tmpl, const struct adb_obj *obj, unsigned i, unsigned mode) { - struct adb_obj o1, o2; - adb_r_obj(__db1, *(adb_val_t *)p1, &o1, __schema); - adb_r_obj(__db2, *(adb_val_t *)p2, &o2, __schema); - return o1.schema->compare(&o1, &o2); -} + const struct adb_object_schema *schema = obj->schema; -static int wadbcmp(const void *p1, const void *p2) -{ - struct adb a1, a2; - struct adb_obj o1, o2; - adb_m_blob(&a1, adb_r_blob(__db1, *(adb_val_t *)p1), 0); - adb_m_blob(&a2, adb_r_blob(__db2, *(adb_val_t *)p2), 0); - adb_r_rootobj(&a1, &o1, __schema); - adb_r_rootobj(&a2, &o2, __schema); - return __schema->compare(&o1, &o2); + assert(schema->kind == ADB_KIND_OBJECT); + assert(schema == tmpl->schema); + assert(i > 0 && i < schema->num_fields); + + switch (*schema->fields[i-1].kind) { + case ADB_KIND_BLOB: + case ADB_KIND_INT: + return container_of(schema->fields[i-1].kind, struct adb_scalar_schema, kind)->compare( + tmpl->db, adb_ro_val(tmpl, i), + obj->db, adb_ro_val(obj, i)); + case ADB_KIND_OBJECT: { + struct adb_obj stmpl, sobj; + adb_ro_obj(tmpl, i, &stmpl); + adb_ro_obj(obj, i, &sobj); + return adb_ro_cmpobj(&stmpl, &sobj, mode); + } + } + assert(!"invalid object field kind"); } -int adb_ra_find(struct adb_obj *arr, int cur, struct adb *db, adb_val_t val) +int adb_ra_find(struct adb_obj *arr, int cur, struct adb_obj *tmpl) { - adb_val_t *ndx; + const struct adb_object_schema *schema = arr->schema, *item_schema; + struct adb_obj obj; - __db1 = db; - __db2 = arr->db; - __schema = arr->schema; - assert(__schema->kind == ADB_KIND_ARRAY); - __schema = container_of(__schema->fields[0].kind, struct adb_object_schema, kind); + assert(schema->kind == ADB_KIND_ARRAY); + assert(*schema->fields[0].kind == ADB_KIND_OBJECT); + item_schema = container_of(schema->fields[0].kind, struct adb_object_schema, kind), + assert(item_schema == tmpl->schema); if (cur == 0) { - ndx = bsearch(&val, &arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wacmp); - if (!ndx) return -1; - cur = ndx - arr->obj; - while (cur > 1 && wacmp(&val, &arr->obj[cur-1]) == 0) cur--; + unsigned m, l = ADBI_FIRST, r = adb_ra_num(arr) + 1; + while (l < r) { + m = (l + r) / 2; + if (adb_ro_cmpobj(tmpl, adb_ro_obj(arr, m, &obj), ADB_OBJCMP_INDEX) < 0) + r = m; + else + l = m + 1; + } + cur = r - 1; } else { cur++; - if (wacmp(&val, &arr->obj[cur]) != 0) - return -1; } - return cur; + for (; cur <= adb_ra_num(arr); cur++) { + adb_ro_obj(arr, cur, &obj); + if (adb_ro_cmpobj(tmpl, &obj, ADB_OBJCMP_TEMPLATE) == 0) return cur; + if (adb_ro_cmpobj(tmpl, &obj, ADB_OBJCMP_INDEX) != 0) return -1; + } + return -1; } /* Write interface */ @@ -566,7 +586,7 @@ static unsigned iovec_memcmp(struct iovec *vec, size_t nvec, void *base) static adb_val_t adb_w_error(struct adb *db, int rc) { - assert(0); + assert(!"adb error"); db->schema = 0; return ADB_ERROR(rc); } @@ -629,43 +649,71 @@ void adb_w_rootobj(struct adb_obj *obj) adb_w_root(obj->db, adb_w_obj(obj)); } -adb_val_t adb_w_blob(struct adb *db, apk_blob_t b) +adb_val_t adb_w_blob_vec(struct adb *db, uint32_t n, apk_blob_t *b) { union { uint32_t u32; uint16_t u16; uint8_t u8; } val; - uint32_t n = b.len; - struct iovec vec[2] = { - { .iov_base = &val, .iov_len = sizeof val }, - { .iov_base = (void *) b.ptr, .iov_len = n }, - }; + const int max_vec_size = 4; + struct iovec vec[1+max_vec_size]; adb_val_t o; + uint32_t i, align = 1; + + assert(n <= max_vec_size); - if (n > 0xffff) { - val.u32 = htole32(n); - vec[0].iov_len = sizeof val.u32; + vec[0] = (struct iovec) { .iov_base = &val, .iov_len = sizeof val }; + for (i = 0; i < n; i++) + vec[i+1] = (struct iovec) { .iov_base = b[i].ptr, .iov_len = b[i].len }; + + size_t sz = iovec_len(&vec[1], n); + if (sz > 0xffff) { + val.u32 = htole32(sz); + vec[0].iov_len = align = sizeof val.u32; o = ADB_TYPE_BLOB_32; - } else if (n > 0xff) { - val.u16 = htole16(n); - vec[0].iov_len = sizeof val.u16; + } else if (sz > 0xff) { + val.u16 = htole16(sz); + vec[0].iov_len = align = sizeof val.u16; o = ADB_TYPE_BLOB_16; - } else if (n > 0) { - val.u8 = n; - vec[0].iov_len = sizeof val.u8; + } else if (sz > 0) { + val.u8 = sz; + vec[0].iov_len = align = sizeof val.u8; o = ADB_TYPE_BLOB_8; } else { return ADB_VAL_NULL; } - return ADB_VAL(o, adb_w_data(db, vec, ARRAY_SIZE(vec), vec[0].iov_len)); + return ADB_VAL(o, adb_w_data(db, vec, n+1, align)); } -adb_val_t adb_w_int(struct adb *db, uint32_t val) +adb_val_t adb_w_blob(struct adb *db, apk_blob_t b) { - if (val >= 0x10000000) - return ADB_VAL(ADB_TYPE_INT_32, adb_w_data1(db, &val, sizeof val, sizeof val)); + return adb_w_blob_vec(db, 1, &b); +} + +static adb_val_t adb_w_blob_raw(struct adb *db, apk_blob_t b) +{ + adb_val_t val; + size_t num_buckets; + + num_buckets = db->num_buckets; + db->num_buckets = 0; + val = adb_w_blob(db, b); + db->num_buckets = num_buckets; + return val; +} + +adb_val_t adb_w_int(struct adb *db, uint64_t val) +{ + if (val >= 0x100000000) { + val = htole64(val); + return ADB_VAL(ADB_TYPE_INT_64, adb_w_data1(db, &val, sizeof val, sizeof val)); + } + if (val >= 0x10000000) { + uint32_t val32 = htole32(val); + return ADB_VAL(ADB_TYPE_INT_32, adb_w_data1(db, &val32, sizeof val32, sizeof val32)); + } return ADB_VAL(ADB_TYPE_INT, val); } @@ -683,6 +731,9 @@ adb_val_t adb_w_copy(struct adb *db, struct adb *srcdb, adb_val_t v) case ADB_TYPE_INT_32: sz = align = sizeof(uint32_t); goto copy; + case ADB_TYPE_INT_64: + sz = align = sizeof(uint64_t); + goto copy; case ADB_TYPE_BLOB_8: ptr = adb_r_deref(srcdb, v, 0, 1); sz = 1UL + *(uint8_t*) ptr; @@ -702,7 +753,6 @@ adb_val_t adb_w_copy(struct adb *db, struct adb *srcdb, adb_val_t v) for (int i = ADBI_FIRST; i < sz; i++) cpy[i] = adb_w_copy(db, srcdb, adb_ro_val(&obj, i)); return ADB_VAL(ADB_VAL_TYPE(v), adb_w_data1(db, cpy, sizeof(adb_val_t[sz]), sizeof(adb_val_t))); } - case ADB_TYPE_INT_64: case ADB_TYPE_BLOB_32: default: return adb_w_error(db, ENOSYS); @@ -718,7 +768,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) }, }; @@ -742,7 +792,7 @@ adb_val_t adb_w_fromstring(struct adb *db, const uint8_t *kind, apk_blob_t val) adb_wo_alloca(&obj, schema, db); if (!schema->fromstring) return ADB_ERROR(APKE_ADB_NO_FROMSTRING); r = schema->fromstring(&obj, val); - if (r) return ADB_ERROR(r); + if (r) return ADB_ERROR(-r); return adb_w_obj(&obj); } default: @@ -785,6 +835,12 @@ struct adb_obj *adb_wo_init_val(struct adb_obj *o, adb_val_t *p, const struct ad return adb_wo_init(o, p, schema, parent->db); } +void adb_wo_free(struct adb_obj *o) +{ + if (o->dynamic) free(o->obj); + o->obj = 0; +} + void adb_wo_reset(struct adb_obj *o) { uint32_t max = o->obj[ADBI_NUM_ENTRIES]; @@ -827,12 +883,26 @@ adb_val_t adb_w_arr(struct adb_obj *o) return __adb_w_obj(o, ADB_TYPE_ARRAY); } -adb_val_t adb_wo_fromstring(struct adb_obj *o, apk_blob_t val) +int adb_wo_fromstring(struct adb_obj *o, apk_blob_t val) { adb_wo_reset(o); return o->schema->fromstring(o, val); } +int adb_wo_copyobj(struct adb_obj *o, struct adb_obj *src) +{ + size_t sz = adb_ro_num(src); + + assert(o->schema->kind == ADB_KIND_OBJECT); + assert(o->schema == src->schema); + + adb_wo_reset(o); + for (unsigned i = ADBI_FIRST; i < sz; i++) + adb_wo_val(o, i, adb_w_copy(o->db, src->db, adb_ro_val(src, i))); + + return 0; +} + adb_val_t adb_wo_val(struct adb_obj *o, unsigned i, adb_val_t v) { if (i >= o->obj[ADBI_NUM_ENTRIES]) return adb_w_error(o->db, E2BIG); @@ -848,7 +918,7 @@ adb_val_t adb_wo_val_fromstring(struct adb_obj *o, unsigned i, apk_blob_t val) return o->obj[i] = adb_w_fromstring(o->db, o->schema->fields[i-1].kind, val); } -adb_val_t adb_wo_int(struct adb_obj *o, unsigned i, uint32_t v) +adb_val_t adb_wo_int(struct adb_obj *o, unsigned i, uint64_t v) { return adb_wo_val(o, i, adb_w_int(o->db, v)); } @@ -859,6 +929,12 @@ adb_val_t adb_wo_blob(struct adb_obj *o, unsigned i, apk_blob_t b) return adb_wo_val(o, i, adb_w_blob(o->db, b)); } +adb_val_t adb_wo_blob_raw(struct adb_obj *o, unsigned i, apk_blob_t b) +{ + assert(o->schema->kind == ADB_KIND_OBJECT); + return adb_wo_val(o, i, adb_w_blob_raw(o->db, b)); +} + adb_val_t adb_wo_obj(struct adb_obj *o, unsigned i, struct adb_obj *no) { assert(o->schema->kind == ADB_KIND_OBJECT); @@ -876,9 +952,20 @@ adb_val_t adb_wo_arr(struct adb_obj *o, unsigned i, struct adb_obj *no) adb_val_t adb_wa_append(struct adb_obj *o, adb_val_t v) { assert(o->schema->kind == ADB_KIND_ARRAY); - if (o->num >= o->obj[ADBI_NUM_ENTRIES]) return adb_w_error(o->db, E2BIG); if (ADB_IS_ERROR(v)) return adb_w_error(o->db, ADB_VAL_VALUE(v)); - if (v != ADB_VAL_NULL) o->obj[o->num++] = v; + if (v == ADB_VAL_NULL) return v; + + if (o->num >= o->obj[ADBI_NUM_ENTRIES]) { + int num = o->obj[ADBI_NUM_ENTRIES]; + adb_val_t *obj = reallocarray(o->dynamic ? o->obj : NULL, num * 2, sizeof(adb_val_t)); + if (!obj) return adb_w_error(o->db, ENOMEM); + if (!o->dynamic) memcpy(obj, o->obj, sizeof(adb_val_t) * num); + memset(&obj[num], 0, sizeof(adb_val_t) * num); + o->obj = obj; + o->obj[ADBI_NUM_ENTRIES] = num * 2; + o->dynamic = 1; + } + o->obj[o->num++] = v; return v; } @@ -895,18 +982,65 @@ adb_val_t adb_wa_append_fromstring(struct adb_obj *o, apk_blob_t b) return adb_wa_append(o, adb_w_fromstring(o->db, o->schema->fields[0].kind, b)); } +struct wacmp_param { + struct adb *db1, *db2; + union { + const struct adb_object_schema *schema; + int (*compare)(struct adb *db1, adb_val_t v1, struct adb *db2, adb_val_t v2); + }; + int mode; +}; + +static int wacmpscalar(const void *p1, const void *p2, void *arg) +{ + struct wacmp_param *wp = arg; + return wp->compare(wp->db1, *(adb_val_t *)p1, wp->db2, *(adb_val_t *)p2); +} + +static int wacmp(const void *p1, const void *p2, void *arg) +{ + struct wacmp_param *wp = arg; + struct adb_obj o1, o2; + adb_r_obj(wp->db1, *(adb_val_t *)p1, &o1, wp->schema); + adb_r_obj(wp->db2, *(adb_val_t *)p2, &o2, wp->schema); + return adb_ro_cmpobj(&o1, &o2, wp->mode); +} + +static int wadbcmp(const void *p1, const void *p2, void *arg) +{ + struct wacmp_param *wp = arg; + struct adb a1, a2; + struct adb_obj o1, o2; + adb_m_blob(&a1, adb_r_blob(wp->db1, *(adb_val_t *)p1), 0); + adb_m_blob(&a2, adb_r_blob(wp->db2, *(adb_val_t *)p2), 0); + adb_r_rootobj(&a1, &o1, wp->schema); + adb_r_rootobj(&a2, &o2, wp->schema); + return adb_ro_cmpobj(&o1, &o2, wp->mode); +} + void adb_wa_sort(struct adb_obj *arr) { - assert(arr->schema->kind == ADB_KIND_ARRAY); - __db1 = __db2 = arr->db; + const struct adb_object_schema *schema = arr->schema; + struct wacmp_param arg = { + .db1 = arr->db, + .db2 = arr->db, + .mode = ADB_OBJCMP_EXACT, + }; + + assert(schema->kind == ADB_KIND_ARRAY); + switch (*arr->schema->fields[0].kind) { + case ADB_KIND_BLOB: + arg.compare = container_of(arr->schema->fields[0].kind, struct adb_scalar_schema, kind)->compare; + qsort_r(&arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wacmpscalar, &arg); + break; case ADB_KIND_OBJECT: - __schema = container_of(arr->schema->fields[0].kind, struct adb_object_schema, kind); - qsort(&arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wacmp); + arg.schema = container_of(arr->schema->fields[0].kind, struct adb_object_schema, kind); + qsort_r(&arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wacmp, &arg); break; case ADB_KIND_ADB: - __schema = container_of(arr->schema->fields[0].kind, struct adb_adb_schema, kind)->schema; - qsort(&arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wadbcmp); + arg.schema = container_of(arr->schema->fields[0].kind, struct adb_adb_schema, kind)->schema; + qsort_r(&arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wadbcmp, &arg); break; default: assert(1); @@ -949,7 +1083,7 @@ int adb_s_field_by_name(const struct adb_object_schema *schema, const char *name int adb_c_header(struct apk_ostream *os, struct adb *db) { struct adb_file_header hdr = { - .magic = ADB_FORMAT_MAGIC, + .magic = htole32(ADB_FORMAT_MAGIC), .schema = htole32(db->schema), }; return apk_ostream_write(os, &hdr, sizeof hdr); @@ -961,9 +1095,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); @@ -977,7 +1109,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); @@ -986,7 +1118,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); @@ -1005,7 +1137,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; @@ -1080,6 +1212,8 @@ static int adb_digest_v0_signature(struct apk_digest_ctx *dctx, uint32_t schema, { int r; + /* it is imporant to normalize this before including it in the digest */ + schema = htole32(schema); if ((r = apk_digest_ctx_update(dctx, &schema, sizeof schema)) != 0 || (r = apk_digest_ctx_update(dctx, sig0, sizeof *sig0)) != 0 || (r = apk_digest_ctx_update(dctx, md.ptr, md.len)) != 0) @@ -1099,8 +1233,6 @@ int adb_trust_write_signatures(struct apk_trust *trust, struct adb *db, struct a size_t siglen; int r; - if (IS_ERR_OR_NULL(trust)) return PTR_ERR(trust); - if (!vfy) { vfy = alloca(sizeof *vfy); memset(vfy, 0, sizeof *vfy); @@ -1118,7 +1250,7 @@ int adb_trust_write_signatures(struct apk_trust *trust, struct adb *db, struct a siglen = sizeof sig.buf - sizeof sig.v0; - if ((r = apk_sign_start(&trust->dctx, &tkey->key)) != 0 || + if ((r = apk_sign_start(&trust->dctx, APK_DIGEST_SHA512, &tkey->key)) != 0 || (r = adb_digest_v0_signature(&trust->dctx, db->schema, &sig.v0, md)) != 0 || (r = apk_sign(&trust->dctx, sig.v0.sig, &siglen)) != 0) goto err; @@ -1150,7 +1282,7 @@ int adb_trust_verify_signature(struct apk_trust *trust, struct adb *db, struct a if (memcmp(sig0->id, tkey->key.id, sizeof sig0->id) != 0) continue; if (adb_digest_adb(vfy, sig->hash_alg, db->adb, &md) != 0) continue; - if (apk_verify_start(&trust->dctx, &tkey->key) != 0 || + if (apk_verify_start(&trust->dctx, APK_DIGEST_SHA512, &tkey->key) != 0 || adb_digest_v0_signature(&trust->dctx, db->schema, sig0, md) != 0 || apk_verify(&trust->dctx, sig0->sig, sigb.len - sizeof *sig0) != 0) continue; |