summaryrefslogtreecommitdiff
path: root/src/gunzip.c
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2018-09-05 19:49:22 +0300
committerTimo Teräs <timo.teras@iki.fi>2018-09-10 10:59:39 +0300
commit6484ed9849f03971eb48ee1fdc21a2f128247eb1 (patch)
treeed0ecf3a027f0497596355ae7895112c5cb99a4a /src/gunzip.c
parentb11f9aa9286320a73a02cd14bfff5974e05a430b (diff)
downloadapk-tools-6484ed9849f03971eb48ee1fdc21a2f128247eb1.tar.gz
apk-tools-6484ed9849f03971eb48ee1fdc21a2f128247eb1.tar.bz2
apk-tools-6484ed9849f03971eb48ee1fdc21a2f128247eb1.tar.xz
apk-tools-6484ed9849f03971eb48ee1fdc21a2f128247eb1.zip
rework unpacking of packages and harden package file format requirements
A crafted .apk file could to trick apk writing unverified data to an unexpected file during temporary file creation due to bugs in handling long link target name and the way a regular file is extracted. Several hardening steps are implemented to avoid this: - the temporary file is now always first unlinked (apk thus reserved all filenames .apk.* to be it's working files) - the temporary file is after that created with O_EXCL to avoid races - the temporary file is no longer directly the archive entry name and thus directly controlled by potentially untrusted data - long file names and link target names are now rejected - hard link targets are now more rigorously checked - various additional checks added for the extraction process to error out early in case of malformed (or old legacy) file Reported-by: Max Justicz <max@justi.cz>
Diffstat (limited to 'src/gunzip.c')
-rw-r--r--src/gunzip.c35
1 files changed, 14 insertions, 21 deletions
diff --git a/src/gunzip.c b/src/gunzip.c
index 4fac9fa..2de841b 100644
--- a/src/gunzip.c
+++ b/src/gunzip.c
@@ -37,6 +37,16 @@ static void gzi_get_meta(void *stream, struct apk_file_meta *meta)
apk_bstream_get_meta(gis->bs, meta);
}
+static int gzi_boundary_change(struct apk_gzip_istream *gis)
+{
+ int r;
+
+ r = gis->cb(gis->cbctx, gis->err ? APK_MPART_END : APK_MPART_BOUNDARY, gis->cbarg);
+ if (r > 0) r = -ECANCELED;
+ if (r != 0) gis->err = r;
+ return r;
+}
+
static ssize_t gzi_read(void *stream, void *ptr, size_t size)
{
struct apk_gzip_istream *gis =
@@ -57,15 +67,8 @@ static ssize_t gzi_read(void *stream, void *ptr, size_t size)
while (gis->zs.avail_out != 0 && gis->err == 0) {
if (!APK_BLOB_IS_NULL(gis->cbarg)) {
- r = gis->cb(gis->cbctx,
- gis->err ? APK_MPART_END : APK_MPART_BOUNDARY,
- gis->cbarg);
- if (r > 0)
- r = -ECANCELED;
- if (r != 0) {
- gis->err = r;
+ if (gzi_boundary_change(gis))
goto ret;
- }
gis->cbarg = APK_BLOB_NULL;
}
if (gis->zs.avail_in == 0) {
@@ -86,14 +89,8 @@ static ssize_t gzi_read(void *stream, void *ptr, size_t size)
goto ret;
} else if (gis->zs.avail_in == 0) {
gis->err = 1;
- if (gis->cb != NULL) {
- r = gis->cb(gis->cbctx, APK_MPART_END,
- APK_BLOB_NULL);
- if (r > 0)
- r = -ECANCELED;
- if (r != 0)
- gis->err = r;
- }
+ gis->cbarg = APK_BLOB_NULL;
+ gzi_boundary_change(gis);
goto ret;
}
}
@@ -115,11 +112,7 @@ static ssize_t gzi_read(void *stream, void *ptr, size_t size)
* For boundaries it should be postponed to not
* be called until next gzip read is started. */
if (gis->err) {
- r = gis->cb(gis->cbctx,
- gis->err ? APK_MPART_END : APK_MPART_BOUNDARY,
- gis->cbarg);
- if (r > 0)
- r = -ECANCELED;
+ gzi_boundary_change(gis);
goto ret;
}
inflateEnd(&gis->zs);