aboutsummaryrefslogtreecommitdiffstats
path: root/src/adb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/adb.c')
-rw-r--r--src/adb.c396
1 files changed, 264 insertions, 132 deletions
diff --git a/src/adb.c b/src/adb.c
index 1fc135c..7759ede 100644
--- a/src/adb.c
+++ b/src/adb.c
@@ -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;