adb: make adb mmap/stream parser more united, add ADB_BLOCK_DATAX
Harden the error checking of expected block types and their order. Add ADB_BLOCK_DATAX as reserved for >1GB blocks.cute-signatures
parent
05364528bb
commit
2f1186aa40
97
src/adb.c
97
src/adb.c
|
@ -76,37 +76,45 @@ static int __adb_m_parse(struct adb *db, apk_blob_t data, struct apk_trust *t,
|
||||||
struct adb_verify_ctx vfy = {};
|
struct adb_verify_ctx vfy = {};
|
||||||
struct adb_block *blk;
|
struct adb_block *blk;
|
||||||
struct apk_istream is;
|
struct apk_istream is;
|
||||||
int r = -APKE_ADB_BLOCK;
|
int r = 0, trusted = t ? 0 : 1;
|
||||||
int trusted = t ? 0 : 1;
|
uint32_t type, allowed = BIT(ADB_BLOCK_ADB);
|
||||||
|
|
||||||
adb_foreach_block(blk, data) {
|
adb_foreach_block(blk, data) {
|
||||||
apk_blob_t b = adb_block_blob(blk);
|
apk_blob_t b = adb_block_blob(blk);
|
||||||
switch (adb_block_type(blk)) {
|
type = adb_block_type(blk);
|
||||||
|
if (!(BIT(type) & allowed)) {
|
||||||
|
r = -APKE_ADB_BLOCK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
case ADB_BLOCK_ADB:
|
case ADB_BLOCK_ADB:
|
||||||
if (!APK_BLOB_IS_NULL(db->adb)) break;
|
allowed = BIT(ADB_BLOCK_SIG) | BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX);
|
||||||
db->adb = b;
|
db->adb = b;
|
||||||
break;
|
break;
|
||||||
case ADB_BLOCK_SIG:
|
case ADB_BLOCK_SIG:
|
||||||
if (APK_BLOB_IS_NULL(db->adb)) break;
|
|
||||||
if (!trusted &&
|
if (!trusted &&
|
||||||
adb_trust_verify_signature(t, db, &vfy, b) == 0)
|
adb_trust_verify_signature(t, db, &vfy, b) == 0)
|
||||||
trusted = 1;
|
trusted = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
case ADB_BLOCK_DATA:
|
||||||
if (APK_BLOB_IS_NULL(db->adb)) break;
|
allowed = BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX);
|
||||||
|
if (!trusted) goto err;
|
||||||
|
break;
|
||||||
|
case ADB_BLOCK_DATAX:
|
||||||
|
r = -APKE_ADB_BLOCK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
r = cb(db, blk, apk_istream_from_blob(&is, b));
|
r = cb(db, blk, apk_istream_from_blob(&is, b));
|
||||||
if (r < 0) goto err;
|
if (r < 0) break;
|
||||||
}
|
}
|
||||||
if (IS_ERR(blk)) r = PTR_ERR(blk);
|
err:
|
||||||
else if (!trusted) r = -APKE_SIGNATURE_UNTRUSTED;
|
if (r > 0) r = -APKE_ADB_BLOCK;
|
||||||
else if (db->adb.ptr) r = 0;
|
if (r == 0) {
|
||||||
|
if (IS_ERR(blk)) r = PTR_ERR(blk);
|
||||||
if (r != 0) {
|
else if (!trusted) r = -APKE_SIGNATURE_UNTRUSTED;
|
||||||
err:
|
else if (!db->adb.ptr) r = -APKE_ADB_BLOCK;
|
||||||
db->adb = APK_BLOB_NULL;
|
|
||||||
}
|
}
|
||||||
|
if (r != 0) db->adb = APK_BLOB_NULL;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,8 +155,8 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec
|
||||||
struct adb_block blk;
|
struct adb_block blk;
|
||||||
struct apk_segment_istream seg;
|
struct apk_segment_istream seg;
|
||||||
void *sig;
|
void *sig;
|
||||||
int r, block_no = 0;
|
int r = 0, trusted = t ? 0 : 1;
|
||||||
int trusted = t ? 0 : 1;
|
uint32_t type, allowed = BIT(ADB_BLOCK_ADB);
|
||||||
size_t sz;
|
size_t sz;
|
||||||
|
|
||||||
if (IS_ERR(is)) return PTR_ERR(is);
|
if (IS_ERR(is)) return PTR_ERR(is);
|
||||||
|
@ -167,20 +175,17 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec
|
||||||
|
|
||||||
do {
|
do {
|
||||||
r = apk_istream_read_max(is, &blk, sizeof blk);
|
r = apk_istream_read_max(is, &blk, sizeof blk);
|
||||||
if (r == 0) {
|
if (r != sizeof blk) break;
|
||||||
if (!trusted) r = -APKE_SIGNATURE_UNTRUSTED;
|
|
||||||
else if (!db->adb.ptr) r = -APKE_ADB_BLOCK;
|
type = adb_block_type(&blk);
|
||||||
goto done;
|
if (!(BIT(type) & allowed)) {
|
||||||
|
r = -APKE_ADB_BLOCK;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (r < 0 || r != sizeof blk) goto err;
|
|
||||||
|
|
||||||
if ((block_no++ == 0) != (adb_block_type(&blk) == ADB_BLOCK_ADB))
|
|
||||||
goto bad_msg;
|
|
||||||
|
|
||||||
sz = adb_block_size(&blk) - sizeof blk;
|
sz = adb_block_size(&blk) - sizeof blk;
|
||||||
switch (adb_block_type(&blk)) {
|
switch (type) {
|
||||||
case ADB_BLOCK_ADB:
|
case ADB_BLOCK_ADB:
|
||||||
if (!APK_BLOB_IS_NULL(db->adb)) goto bad_msg;
|
allowed = BIT(ADB_BLOCK_SIG) | BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX);
|
||||||
db->adb.ptr = malloc(sz);
|
db->adb.ptr = malloc(sz);
|
||||||
db->adb.len = adb_block_length(&blk);
|
db->adb.len = adb_block_length(&blk);
|
||||||
if ((r = apk_istream_read(is, db->adb.ptr, sz)) < 0) goto err;
|
if ((r = apk_istream_read(is, db->adb.ptr, sz)) < 0) goto err;
|
||||||
|
@ -188,7 +193,6 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec
|
||||||
if (r < 0) goto err;
|
if (r < 0) goto err;
|
||||||
continue;
|
continue;
|
||||||
case ADB_BLOCK_SIG:
|
case ADB_BLOCK_SIG:
|
||||||
if (APK_BLOB_IS_NULL(db->adb)) goto bad_msg;
|
|
||||||
sig = apk_istream_peek(is, sz);
|
sig = apk_istream_peek(is, sz);
|
||||||
if (IS_ERR(sig)) {
|
if (IS_ERR(sig)) {
|
||||||
r = PTR_ERR(sig);
|
r = PTR_ERR(sig);
|
||||||
|
@ -199,27 +203,30 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec
|
||||||
trusted = 1;
|
trusted = 1;
|
||||||
break;
|
break;
|
||||||
case ADB_BLOCK_DATA:
|
case ADB_BLOCK_DATA:
|
||||||
if (APK_BLOB_IS_NULL(db->adb)) goto bad_msg;
|
allowed = BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX);
|
||||||
if (!trusted) {
|
if (!trusted) goto err;
|
||||||
r = -APKE_SIGNATURE_UNTRUSTED;
|
break;
|
||||||
goto err;
|
case ADB_BLOCK_DATAX:
|
||||||
}
|
r = -APKE_ADB_BLOCK;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
goto bad_msg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apk_istream_segment(&seg, is, adb_block_size(&blk) - sizeof blk, 0);
|
apk_istream_segment(&seg, is, sz, 0);
|
||||||
r = cb(db, &blk, &seg.is);
|
r = cb(db, &blk, &seg.is);
|
||||||
if (r < 0) goto err;
|
if (r < 0) break;
|
||||||
r = apk_istream_close(&seg.is);
|
r = apk_istream_close(&seg.is);
|
||||||
if (r < 0) goto err;
|
if (r < 0) break;
|
||||||
} while (1);
|
} while (1);
|
||||||
bad_msg:
|
|
||||||
r = -APKE_ADB_BLOCK;
|
|
||||||
err:
|
err:
|
||||||
if (r >= 0) r = -APKE_ADB_BLOCK;
|
if (r > 0) r = -APKE_ADB_BLOCK;
|
||||||
done:
|
if (r == 0) {
|
||||||
|
if (!trusted) r = -APKE_SIGNATURE_UNTRUSTED;
|
||||||
|
else if (!db->adb.ptr) r = -APKE_ADB_BLOCK;
|
||||||
|
}
|
||||||
|
if (r != 0) {
|
||||||
|
free(db->adb.ptr);
|
||||||
|
db->adb = APK_BLOB_NULL;
|
||||||
|
}
|
||||||
return apk_istream_close_error(is, r);
|
return apk_istream_close_error(is, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -929,6 +936,8 @@ int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t val)
|
||||||
size_t padding = adb_block_padding(&blk);
|
size_t padding = adb_block_padding(&blk);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
if (val.len & ~0x3fffffff) return -APKE_ADB_LIMIT;
|
||||||
|
|
||||||
r = apk_ostream_write(os, &blk, sizeof blk);
|
r = apk_ostream_write(os, &blk, sizeof blk);
|
||||||
if (r < 0) return r;
|
if (r < 0) return r;
|
||||||
|
|
||||||
|
@ -990,6 +999,8 @@ int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_ist
|
||||||
} else {
|
} else {
|
||||||
r = apk_stream_copy(is, os, blk_sz, 0, 0, 0);
|
r = apk_stream_copy(is, os, blk_sz, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
if (r < 0) return r;
|
||||||
|
r = 0;
|
||||||
if (padding) {
|
if (padding) {
|
||||||
r = apk_ostream_write(os, padding_zeroes, padding);
|
r = apk_ostream_write(os, padding_zeroes, padding);
|
||||||
if (r < 0) return r;
|
if (r < 0) return r;
|
||||||
|
|
|
@ -54,8 +54,9 @@ struct adb_header {
|
||||||
/* Blocks */
|
/* Blocks */
|
||||||
#define ADB_BLOCK_ALIGNMENT 8
|
#define ADB_BLOCK_ALIGNMENT 8
|
||||||
#define ADB_BLOCK_ADB 0
|
#define ADB_BLOCK_ADB 0
|
||||||
#define ADB_BLOCK_SIG 2
|
#define ADB_BLOCK_SIG 1
|
||||||
#define ADB_BLOCK_DATA 3
|
#define ADB_BLOCK_DATA 2
|
||||||
|
#define ADB_BLOCK_DATAX 3
|
||||||
|
|
||||||
struct adb_block {
|
struct adb_block {
|
||||||
uint32_t type_size;
|
uint32_t type_size;
|
||||||
|
|
|
@ -16,6 +16,7 @@ struct apk_istream *adb_decompress(struct apk_istream *is, adb_comp_t *compressi
|
||||||
if (IS_ERR_OR_NULL(is)) return is;
|
if (IS_ERR_OR_NULL(is)) return is;
|
||||||
|
|
||||||
uint8_t *buf = apk_istream_peek(is, 4);
|
uint8_t *buf = apk_istream_peek(is, 4);
|
||||||
|
if (IS_ERR(buf)) return ERR_PTR(apk_istream_close_error(is, PTR_ERR(buf)));
|
||||||
if (memcmp(buf, "ADB", 3) == 0) switch (buf[3]) {
|
if (memcmp(buf, "ADB", 3) == 0) switch (buf[3]) {
|
||||||
case '.':
|
case '.':
|
||||||
c = ADB_COMP_NONE;
|
c = ADB_COMP_NONE;
|
||||||
|
|
|
@ -84,10 +84,11 @@ static int adbsign_main(void *pctx, struct apk_ctx *ac, struct apk_string_array
|
||||||
|
|
||||||
ctx->ac = ac;
|
ctx->ac = ac;
|
||||||
foreach_array_item(arg, args) {
|
foreach_array_item(arg, args) {
|
||||||
|
memset(&ctx->vfy, 0, sizeof ctx->vfy);
|
||||||
struct apk_istream *is = adb_decompress(apk_istream_from_file_mmap(AT_FDCWD, *arg), &comp);
|
struct apk_istream *is = adb_decompress(apk_istream_from_file_mmap(AT_FDCWD, *arg), &comp);
|
||||||
ctx->os = adb_compress(apk_ostream_to_file(AT_FDCWD, *arg, 0644), comp);
|
ctx->os = adb_compress(apk_ostream_to_file(AT_FDCWD, *arg, 0644), comp);
|
||||||
adb_m_process(&ctx->db, is, 0, 0, process_block);
|
apk_ostream_cancel(ctx->os, adb_m_process(&ctx->db, is, 0, 0, process_block));
|
||||||
process_signatures(ctx);
|
apk_ostream_cancel(ctx->os, process_signatures(ctx));
|
||||||
adb_free(&ctx->db);
|
adb_free(&ctx->db);
|
||||||
r = apk_ostream_close(ctx->os);
|
r = apk_ostream_close(ctx->os);
|
||||||
if (r) apk_err(out, "%s: %s", *arg, apk_error_str(r));
|
if (r) apk_err(out, "%s: %s", *arg, apk_error_str(r));
|
||||||
|
|
Loading…
Reference in New Issue