summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2023-09-11 13:09:58 +0300
committerTimo Teräs <timo.teras@iki.fi>2023-10-15 16:39:10 +0000
commitc5d8d286f6920542a73232d503d92e9a82b7be58 (patch)
tree5b49182c230c2c0d26dd540e3db9e12de926149d
parent9410e486ce6b95b22b42ea5d7c712c17962aade5 (diff)
downloadapk-tools-c5d8d286f6920542a73232d503d92e9a82b7be58.tar.gz
apk-tools-c5d8d286f6920542a73232d503d92e9a82b7be58.tar.bz2
apk-tools-c5d8d286f6920542a73232d503d92e9a82b7be58.tar.xz
apk-tools-c5d8d286f6920542a73232d503d92e9a82b7be58.zip
adb: implement ADB_BLOCK_EXT flavor for large files
-rw-r--r--src/adb.c46
-rw-r--r--src/adb.h38
-rw-r--r--src/adb_walk_adb.c6
-rw-r--r--src/extract_v3.c2
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;