From 7e585512f4409eb4e1635ed4d58e9c9774495dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Sat, 17 Jul 2021 23:21:16 +0300 Subject: [PATCH] io: make apk_istream_get/read() fail on incomplete read --- src/adb.c | 6 ++--- src/apk_io.h | 5 ++-- src/io.c | 60 ++++++++++++++++++++++-------------------------- src/io_archive.c | 10 ++++---- src/package.c | 22 +++++------------- 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; + apk_blob_t b; - if (type >= APK_SCRIPT_MAX) - return -1; - - ptr = malloc(size); - r = apk_istream_read(is, ptr, size); - if (r < 0) { - free(ptr); - return r; - } - - 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; }