io: make apk_istream_get/read() fail on incomplete read
parent
395e92b66e
commit
7e585512f4
|
@ -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 (IS_ERR(is)) return PTR_ERR(is);
|
||||||
|
|
||||||
if (!(expected_schema & ADB_SCHEMA_IMPLIED)) {
|
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)) {
|
if (db->hdr.magic != htole32(ADB_FORMAT_MAGIC)) {
|
||||||
r = -APKE_ADB_HEADER;
|
r = -APKE_ADB_HEADER;
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -166,7 +166,7 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
r = apk_istream_read(is, &blk, sizeof blk);
|
r = apk_istream_read_max(is, &blk, sizeof blk);
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
if (!trusted) r = -APKE_SIGNATURE_UNTRUSTED;
|
if (!trusted) r = -APKE_SIGNATURE_UNTRUSTED;
|
||||||
else if (!db->adb.ptr) r = -APKE_ADB_BLOCK;
|
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;
|
if (!APK_BLOB_IS_NULL(db->adb)) goto bad_msg;
|
||||||
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)) != 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));
|
r = cb(db, &blk, apk_istream_from_blob(&seg.is, db->adb));
|
||||||
if (r < 0) goto err;
|
if (r < 0) goto err;
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -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); }
|
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(int fd);
|
||||||
struct apk_istream *apk_istream_from_fd_url_if_modified(int atfd, const char *url, time_t since);
|
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);
|
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_peek(struct apk_istream *is, size_t len);
|
||||||
void *apk_istream_get(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);
|
int apk_istream_get_max(struct apk_istream *is, size_t size, apk_blob_t *data);
|
||||||
|
|
60
src/io.c
60
src/io.c
|
@ -68,7 +68,7 @@ apk_blob_t apk_istream_mmap(struct apk_istream *is)
|
||||||
return APK_BLOB_NULL;
|
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;
|
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;
|
is->end = is->buf + r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r < 0) return r;
|
if (r < 0) return apk_istream_error(is, r);
|
||||||
if (size && left == size && !is->err) is->err = 1;
|
if (left == size) return apk_istream_error(is, (size && !is->err) ? 1 : 0);
|
||||||
if (size == left) return is->err < 0 ? is->err : 0;
|
|
||||||
return size - left;
|
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)
|
static int __apk_istream_fill(struct apk_istream *is)
|
||||||
{
|
{
|
||||||
ssize_t sz;
|
ssize_t sz;
|
||||||
|
@ -117,51 +122,46 @@ static int __apk_istream_fill(struct apk_istream *is)
|
||||||
memmove(is->buf, is->ptr, sz);
|
memmove(is->buf, is->ptr, sz);
|
||||||
is->ptr = is->buf;
|
is->ptr = is->buf;
|
||||||
is->end = is->buf + sz;
|
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);
|
sz = is->ops->read(is, is->end, is->buf + is->buf_size - is->end);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) return apk_istream_error(is, sz ?: 1);
|
||||||
is->err = sz ?: 1;
|
|
||||||
return is->err;
|
|
||||||
}
|
|
||||||
is->end += sz;
|
is->end += sz;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *apk_istream_peek(struct apk_istream *is, size_t len)
|
void *apk_istream_peek(struct apk_istream *is, size_t len)
|
||||||
{
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (is->end - is->ptr >= len) {
|
if (is->end - is->ptr >= len) {
|
||||||
void *ptr = is->ptr;
|
void *ptr = is->ptr;
|
||||||
return 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(r > 0 ? -APKE_EOF : r);
|
||||||
return ERR_PTR(-ENOBUFS);
|
|
||||||
if (is->err > 0)
|
|
||||||
return ERR_PTR(-APKE_EOF);
|
|
||||||
return ERR_PTR(-EIO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *apk_istream_get(struct apk_istream *is, size_t len)
|
void *apk_istream_get(struct apk_istream *is, size_t len)
|
||||||
{
|
{
|
||||||
void *p = apk_istream_peek(is, len);
|
void *p = apk_istream_peek(is, len);
|
||||||
if (!IS_ERR_OR_NULL(p)) is->ptr += len;
|
if (!IS_ERR_OR_NULL(p)) is->ptr += len;
|
||||||
|
else apk_istream_error(is, PTR_ERR(p));
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
int apk_istream_get_max(struct apk_istream *is, size_t max, apk_blob_t *data)
|
int apk_istream_get_max(struct apk_istream *is, size_t max, apk_blob_t *data)
|
||||||
{
|
{
|
||||||
if (is->ptr == is->end)
|
if (is->ptr == is->end) __apk_istream_fill(is);
|
||||||
__apk_istream_fill(is);
|
|
||||||
|
|
||||||
if (is->ptr != is->end) {
|
if (is->ptr != is->end) {
|
||||||
*data = APK_BLOB_PTR_LEN((char*)is->ptr, min((size_t)(is->end - is->ptr), max));
|
*data = APK_BLOB_PTR_LEN((char*)is->ptr, min((size_t)(is->end - is->ptr), max));
|
||||||
is->ptr += data->len;
|
is->ptr += data->len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*data = APK_BLOB_NULL;
|
*data = APK_BLOB_NULL;
|
||||||
return is->err < 0 ? is->err : -APKE_EOF;
|
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)
|
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;
|
apk_blob_t ret = APK_BLOB_NULL, left = APK_BLOB_NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (apk_blob_split(APK_BLOB_PTR_LEN((char*)is->ptr, is->end - is->ptr), token, &ret, &left))
|
if (apk_blob_split(APK_BLOB_PTR_LEN((char*)is->ptr, is->end - is->ptr), token, &ret, &left))
|
||||||
break;
|
break;
|
||||||
if (is->end - is->ptr == is->buf_size) {
|
r = __apk_istream_fill(is);
|
||||||
is->err = -ENOBUFS;
|
} while (r == 0);
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (!__apk_istream_fill(is));
|
|
||||||
|
|
||||||
/* Last segment before end-of-file. Return also zero length non-null
|
/* Last segment before end-of-file. Return also zero length non-null
|
||||||
* blob if eof comes immediately after the delimiter. */
|
* 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);
|
ret = APK_BLOB_PTR_LEN((char*)is->ptr, is->end - is->ptr);
|
||||||
|
|
||||||
if (!APK_BLOB_IS_NULL(ret)) {
|
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;
|
*data = ret;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (r < 0) apk_istream_error(is, r);
|
||||||
*data = APK_BLOB_NULL;
|
*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)
|
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)
|
apk_blob_t apk_blob_from_istream(struct apk_istream *is, size_t size)
|
||||||
{
|
{
|
||||||
void *ptr;
|
void *ptr;
|
||||||
ssize_t rsize;
|
|
||||||
|
|
||||||
ptr = malloc(size);
|
ptr = malloc(size);
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
return APK_BLOB_NULL;
|
return APK_BLOB_NULL;
|
||||||
|
|
||||||
rsize = apk_istream_read(is, ptr, size);
|
if (apk_istream_read(is, ptr, size) < 0) {
|
||||||
if (rsize < 0) {
|
|
||||||
free(ptr);
|
free(ptr);
|
||||||
return APK_BLOB_NULL;
|
return APK_BLOB_NULL;
|
||||||
}
|
}
|
||||||
if (rsize != size)
|
return APK_BLOB_PTR_LEN(ptr, size);
|
||||||
ptr = realloc(ptr, rsize);
|
|
||||||
|
|
||||||
return APK_BLOB_PTR_LEN(ptr, rsize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apk_blob_t apk_blob_from_file(int atfd, const char *file)
|
apk_blob_t apk_blob_from_file(int atfd, const char *file)
|
||||||
|
|
|
@ -141,7 +141,7 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
|
||||||
|
|
||||||
memset(&entry, 0, sizeof(entry));
|
memset(&entry, 0, sizeof(entry));
|
||||||
entry.name = buf.name;
|
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 (buf.name[0] == '\0') {
|
||||||
if (end) break;
|
if (end) break;
|
||||||
end++;
|
end++;
|
||||||
|
@ -182,7 +182,7 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
|
||||||
switch (buf.typeflag) {
|
switch (buf.typeflag) {
|
||||||
case 'L': /* GNU long name extension */
|
case 'L': /* GNU long name extension */
|
||||||
if ((r = blob_realloc(&longname, entry.size+1)) != 0 ||
|
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;
|
goto err;
|
||||||
longname.ptr[entry.size] = 0;
|
longname.ptr[entry.size] = 0;
|
||||||
entry.name = longname.ptr;
|
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 */
|
case 'x': /* file specific pax header */
|
||||||
paxlen = entry.size;
|
paxlen = entry.size;
|
||||||
if ((r = blob_realloc(&pax, (paxlen + 511) & -512)) != 0 ||
|
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;
|
goto err;
|
||||||
toskip -= entry.size;
|
toskip -= entry.size;
|
||||||
break;
|
break;
|
||||||
|
@ -244,14 +244,14 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
|
||||||
paxlen = 0;
|
paxlen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toskip && (r = apk_istream_read(is, NULL, toskip)) != toskip)
|
if (toskip && (r = apk_istream_read(is, NULL, toskip)) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read remaining end-of-archive records, to ensure we read all of
|
/* Read remaining end-of-archive records, to ensure we read all of
|
||||||
* the file. The underlying istream is likely doing checksumming. */
|
* the file. The underlying istream is likely doing checksumming. */
|
||||||
if (r == 512) {
|
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;
|
if (buf.name[0] != 0) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -976,23 +976,13 @@ int apk_ipkg_add_script(struct apk_installed_package *ipkg,
|
||||||
struct apk_istream *is,
|
struct apk_istream *is,
|
||||||
unsigned int type, unsigned int size)
|
unsigned int type, unsigned int size)
|
||||||
{
|
{
|
||||||
void *ptr;
|
apk_blob_t b;
|
||||||
int r;
|
|
||||||
|
|
||||||
if (type >= APK_SCRIPT_MAX)
|
if (type >= APK_SCRIPT_MAX) return -1;
|
||||||
return -1;
|
b = apk_blob_from_istream(is, size);
|
||||||
|
if (APK_BLOB_IS_NULL(b)) return -1;
|
||||||
ptr = malloc(size);
|
if (ipkg->script[type].ptr) free(ipkg->script[type].ptr);
|
||||||
r = apk_istream_read(is, ptr, size);
|
ipkg->script[type] = b;
|
||||||
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;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue