summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2021-07-17 23:21:16 +0300
committerTimo Teräs <timo.teras@iki.fi>2021-07-22 15:30:08 +0300
commit7e585512f4409eb4e1635ed4d58e9c9774495dfa (patch)
treea47e9a278ab9178e0dde9cc3ff937b0b4c5a96b2
parent395e92b66e35ccbd2f07a4857d6da588ec9f51f2 (diff)
downloadapk-tools-7e585512f4409eb4e1635ed4d58e9c9774495dfa.tar.gz
apk-tools-7e585512f4409eb4e1635ed4d58e9c9774495dfa.tar.bz2
apk-tools-7e585512f4409eb4e1635ed4d58e9c9774495dfa.tar.xz
apk-tools-7e585512f4409eb4e1635ed4d58e9c9774495dfa.zip
io: make apk_istream_get/read() fail on incomplete read
-rw-r--r--src/adb.c6
-rw-r--r--src/apk_io.h5
-rw-r--r--src/io.c60
-rw-r--r--src/io_archive.c10
-rw-r--r--src/package.c22
5 files changed, 44 insertions, 59 deletions
diff --git a/src/adb.c b/src/adb.c
index a4fe612..064cf6b 100644
--- a/src/adb.c
+++ b/src/adb.c
@@ -154,7 +154,7 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec
if (IS_ERR(is)) return PTR_ERR(is);
if (!(expected_schema & ADB_SCHEMA_IMPLIED)) {
- if ((r = apk_istream_read(is, &db->hdr, sizeof db->hdr)) != sizeof db->hdr) goto err;
+ if ((r = apk_istream_read(is, &db->hdr, sizeof db->hdr)) < 0) goto err;
if (db->hdr.magic != htole32(ADB_FORMAT_MAGIC)) {
r = -APKE_ADB_HEADER;
goto err;
@@ -166,7 +166,7 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec
}
do {
- r = apk_istream_read(is, &blk, sizeof blk);
+ r = apk_istream_read_max(is, &blk, sizeof blk);
if (r == 0) {
if (!trusted) r = -APKE_SIGNATURE_UNTRUSTED;
else if (!db->adb.ptr) r = -APKE_ADB_BLOCK;
@@ -183,7 +183,7 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec
if (!APK_BLOB_IS_NULL(db->adb)) goto bad_msg;
db->adb.ptr = malloc(sz);
db->adb.len = adb_block_length(&blk);
- if ((r = apk_istream_read(is, db->adb.ptr, sz)) != sz) goto err;
+ if ((r = apk_istream_read(is, db->adb.ptr, sz)) < 0) goto err;
r = cb(db, &blk, apk_istream_from_blob(&seg.is, db->adb));
if (r < 0) goto err;
continue;
diff --git a/src/apk_io.h b/src/apk_io.h
index d03369e..50464a9 100644
--- a/src/apk_io.h
+++ b/src/apk_io.h
@@ -92,9 +92,10 @@ static inline struct apk_istream *apk_istream_from_file(int atfd, const char *fi
static inline struct apk_istream *apk_istream_from_file_mmap(int atfd, const char *file) { return __apk_istream_from_file(atfd, file, 1); }
struct apk_istream *apk_istream_from_fd(int fd);
struct apk_istream *apk_istream_from_fd_url_if_modified(int atfd, const char *url, time_t since);
-static inline int apk_istream_error(struct apk_istream *is, int err) { if (!is->err) is->err = err; return err; }
+static inline int apk_istream_error(struct apk_istream *is, int err) { if (is->err >= 0 && err) is->err = err; return is->err < 0 ? is->err : 0; }
apk_blob_t apk_istream_mmap(struct apk_istream *is);
-ssize_t apk_istream_read(struct apk_istream *is, void *ptr, size_t size);
+ssize_t apk_istream_read_max(struct apk_istream *is, void *ptr, size_t size);
+int apk_istream_read(struct apk_istream *is, void *ptr, size_t size);
void *apk_istream_peek(struct apk_istream *is, size_t len);
void *apk_istream_get(struct apk_istream *is, size_t len);
int apk_istream_get_max(struct apk_istream *is, size_t size, apk_blob_t *data);
diff --git a/src/io.c b/src/io.c
index bb5c566..6628c36 100644
--- a/src/io.c
+++ b/src/io.c
@@ -68,7 +68,7 @@ apk_blob_t apk_istream_mmap(struct apk_istream *is)
return APK_BLOB_NULL;
}
-ssize_t apk_istream_read(struct apk_istream *is, void *ptr, size_t size)
+ssize_t apk_istream_read_max(struct apk_istream *is, void *ptr, size_t size)
{
ssize_t left = size, r = 0;
@@ -100,12 +100,17 @@ ssize_t apk_istream_read(struct apk_istream *is, void *ptr, size_t size)
is->end = is->buf + r;
}
- if (r < 0) return r;
- if (size && left == size && !is->err) is->err = 1;
- if (size == left) return is->err < 0 ? is->err : 0;
+ if (r < 0) return apk_istream_error(is, r);
+ if (left == size) return apk_istream_error(is, (size && !is->err) ? 1 : 0);
return size - left;
}
+int apk_istream_read(struct apk_istream *is, void *ptr, size_t size)
+{
+ ssize_t r = apk_istream_read_max(is, ptr, size);
+ return r == size ? 0 : apk_istream_error(is, -APKE_EOF);
+}
+
static int __apk_istream_fill(struct apk_istream *is)
{
ssize_t sz;
@@ -117,51 +122,46 @@ static int __apk_istream_fill(struct apk_istream *is)
memmove(is->buf, is->ptr, sz);
is->ptr = is->buf;
is->end = is->buf + sz;
- }
+ } else if (is->end-is->ptr == is->buf_size)
+ return -ENOBUFS;
sz = is->ops->read(is, is->end, is->buf + is->buf_size - is->end);
- if (sz <= 0) {
- is->err = sz ?: 1;
- return is->err;
- }
+ if (sz <= 0) return apk_istream_error(is, sz ?: 1);
is->end += sz;
return 0;
}
void *apk_istream_peek(struct apk_istream *is, size_t len)
{
+ int r;
+
do {
if (is->end - is->ptr >= len) {
void *ptr = is->ptr;
return ptr;
}
- } while (!__apk_istream_fill(is));
+ r = __apk_istream_fill(is);
+ } while (r == 0);
- if (is->end-is->ptr == is->buf_size)
- return ERR_PTR(-ENOBUFS);
- if (is->err > 0)
- return ERR_PTR(-APKE_EOF);
- return ERR_PTR(-EIO);
+ return ERR_PTR(r > 0 ? -APKE_EOF : r);
}
void *apk_istream_get(struct apk_istream *is, size_t len)
{
void *p = apk_istream_peek(is, len);
if (!IS_ERR_OR_NULL(p)) is->ptr += len;
+ else apk_istream_error(is, PTR_ERR(p));
return p;
}
int apk_istream_get_max(struct apk_istream *is, size_t max, apk_blob_t *data)
{
- if (is->ptr == is->end)
- __apk_istream_fill(is);
-
+ if (is->ptr == is->end) __apk_istream_fill(is);
if (is->ptr != is->end) {
*data = APK_BLOB_PTR_LEN((char*)is->ptr, min((size_t)(is->end - is->ptr), max));
is->ptr += data->len;
return 0;
}
-
*data = APK_BLOB_NULL;
return is->err < 0 ? is->err : -APKE_EOF;
}
@@ -169,19 +169,17 @@ int apk_istream_get_max(struct apk_istream *is, size_t max, apk_blob_t *data)
int apk_istream_get_delim(struct apk_istream *is, apk_blob_t token, apk_blob_t *data)
{
apk_blob_t ret = APK_BLOB_NULL, left = APK_BLOB_NULL;
+ int r;
do {
if (apk_blob_split(APK_BLOB_PTR_LEN((char*)is->ptr, is->end - is->ptr), token, &ret, &left))
break;
- if (is->end - is->ptr == is->buf_size) {
- is->err = -ENOBUFS;
- break;
- }
- } while (!__apk_istream_fill(is));
+ r = __apk_istream_fill(is);
+ } while (r == 0);
/* Last segment before end-of-file. Return also zero length non-null
* blob if eof comes immediately after the delimiter. */
- if (is->ptr && is->err > 0)
+ if (is->ptr && r > 0)
ret = APK_BLOB_PTR_LEN((char*)is->ptr, is->end - is->ptr);
if (!APK_BLOB_IS_NULL(ret)) {
@@ -190,8 +188,9 @@ int apk_istream_get_delim(struct apk_istream *is, apk_blob_t token, apk_blob_t *
*data = ret;
return 0;
}
+ if (r < 0) apk_istream_error(is, r);
*data = APK_BLOB_NULL;
- return is->err < 0 ? is->err : -APKE_EOF;
+ return r < 0 ? r : -APKE_EOF;
}
static void blob_get_meta(struct apk_istream *is, struct apk_file_meta *meta)
@@ -571,21 +570,16 @@ ssize_t apk_stream_copy(struct apk_istream *is, struct apk_ostream *os, size_t s
apk_blob_t apk_blob_from_istream(struct apk_istream *is, size_t size)
{
void *ptr;
- ssize_t rsize;
ptr = malloc(size);
if (ptr == NULL)
return APK_BLOB_NULL;
- rsize = apk_istream_read(is, ptr, size);
- if (rsize < 0) {
+ if (apk_istream_read(is, ptr, size) < 0) {
free(ptr);
return APK_BLOB_NULL;
}
- if (rsize != size)
- ptr = realloc(ptr, rsize);
-
- return APK_BLOB_PTR_LEN(ptr, rsize);
+ return APK_BLOB_PTR_LEN(ptr, size);
}
apk_blob_t apk_blob_from_file(int atfd, const char *file)
diff --git a/src/io_archive.c b/src/io_archive.c
index 1164d7c..ccd512a 100644
--- a/src/io_archive.c
+++ b/src/io_archive.c
@@ -141,7 +141,7 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
memset(&entry, 0, sizeof(entry));
entry.name = buf.name;
- while ((r = apk_istream_read(is, &buf, 512)) == 512) {
+ while ((r = apk_istream_read_max(is, &buf, 512)) == 512) {
if (buf.name[0] == '\0') {
if (end) break;
end++;
@@ -182,7 +182,7 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
switch (buf.typeflag) {
case 'L': /* GNU long name extension */
if ((r = blob_realloc(&longname, entry.size+1)) != 0 ||
- (r = apk_istream_read(is, longname.ptr, entry.size)) != entry.size)
+ (r = apk_istream_read(is, longname.ptr, entry.size)) < 0)
goto err;
longname.ptr[entry.size] = 0;
entry.name = longname.ptr;
@@ -219,7 +219,7 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
case 'x': /* file specific pax header */
paxlen = entry.size;
if ((r = blob_realloc(&pax, (paxlen + 511) & -512)) != 0 ||
- (r = apk_istream_read(is, pax.ptr, paxlen)) != paxlen)
+ (r = apk_istream_read(is, pax.ptr, paxlen)) < 0)
goto err;
toskip -= entry.size;
break;
@@ -244,14 +244,14 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
paxlen = 0;
}
- if (toskip && (r = apk_istream_read(is, NULL, toskip)) != toskip)
+ if (toskip && (r = apk_istream_read(is, NULL, toskip)) < 0)
goto err;
}
/* Read remaining end-of-archive records, to ensure we read all of
* the file. The underlying istream is likely doing checksumming. */
if (r == 512) {
- while ((r = apk_istream_read(is, &buf, 512)) == 512) {
+ while ((r = apk_istream_read_max(is, &buf, 512)) == 512) {
if (buf.name[0] != 0) break;
}
}
diff --git a/src/package.c b/src/package.c
index dee15eb..fd0104a 100644
--- a/src/package.c
+++ b/src/package.c
@@ -976,23 +976,13 @@ int apk_ipkg_add_script(struct apk_installed_package *ipkg,
struct apk_istream *is,
unsigned int type, unsigned int size)
{
- void *ptr;
- int r;
-
- if (type >= APK_SCRIPT_MAX)
- return -1;
-
- ptr = malloc(size);
- r = apk_istream_read(is, ptr, size);
- if (r < 0) {
- free(ptr);
- return r;
- }
+ apk_blob_t b;
- if (ipkg->script[type].ptr)
- free(ipkg->script[type].ptr);
- ipkg->script[type].ptr = ptr;
- ipkg->script[type].len = size;
+ if (type >= APK_SCRIPT_MAX) return -1;
+ b = apk_blob_from_istream(is, size);
+ if (APK_BLOB_IS_NULL(b)) return -1;
+ if (ipkg->script[type].ptr) free(ipkg->script[type].ptr);
+ ipkg->script[type] = b;
return 0;
}