io: make apk_istream_get/read() fail on incomplete read

cute-signatures
Timo Teräs 2021-07-17 23:21:16 +03:00
parent 395e92b66e
commit 7e585512f4
5 changed files with 44 additions and 59 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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;
}