aboutsummaryrefslogtreecommitdiff
path: root/src/io.c
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2025-12-03 03:00:10 -0500
committerB. Watson <urchlay@slackware.uk>2025-12-03 03:00:10 -0500
commitfff0d9587f674e2b1f61ba693ef830862dc1241d (patch)
tree20a9d4d1e9fb145f2c2d937a478aa220f16da728 /src/io.c
parent939dab58d23272a68c16c625dbd14ff3f8f6c51b (diff)
downloadalftools-fff0d9587f674e2b1f61ba693ef830862dc1241d.tar.gz
unalf: Abort on ludicrously large sizes in the header. Add -F to bypass, warn the user this may cause an infinite loop.
Diffstat (limited to 'src/io.c')
-rw-r--r--src/io.c48
1 files changed, 39 insertions, 9 deletions
diff --git a/src/io.c b/src/io.c
index 53bc0dd..9a0486d 100644
--- a/src/io.c
+++ b/src/io.c
@@ -28,6 +28,7 @@ static void eof_junk(long pos) {
static void check_hdr_size(const char *name, unsigned long size) {
const char *desc;
+ int fatal = 0;
/* fits on a double-density disk? */
if(size < 184320)
@@ -35,22 +36,51 @@ static void check_hdr_size(const char *name, unsigned long size) {
/* >= 16MB files are impossible because the decrunch algorithm
ignores the high byte of the 4-byte length. */
- if(size >= 16777216L)
+ if(size >= 16777216L) {
desc = "impossibly large (>=16MB)";
+ fatal = !opts.listonly; /* listing the file isn't an error, extracting it is. */
/* >1MB files are possible (e.g. with a hard drive on SpartaDOS X)
but exceedingly rare in the Atari world. */
- else if(size > 1048576L)
+ } else if(size > 1048576L) {
desc = "suspiciously large (>1MB)";
- else
+ } else {
desc = "too large for a floppy disk (>180KB)";
+ }
- fprintf(stderr, "%s: header #%d %s size is %s.\n",
- self, headers_read, name, desc);
+ fprintf(stderr, "%s: %s: header #%d %s size is %s.\n",
+ self, (fatal ? "fatal" : "warning"), headers_read, name, desc);
+ if(fatal) exit(1);
}
-static void sanity_check_header(void) {
- check_hdr_size("original", getquad(alf_hdr_origsize0));
- check_hdr_size("compressed", getquad(alf_hdr_compsize0));
+static void sanity_check_header(long pos) {
+ struct stat s;
+ unsigned long origsize, compsize;
+ int fatal;
+
+ origsize = getquad(alf_hdr_origsize0);
+ compsize = getquad(alf_hdr_compsize0);
+
+ check_hdr_size("original", origsize);
+ check_hdr_size("compressed", compsize);
+
+ pos += 29; /* skip header */
+ if(fstat(fileno(in_file), &s) < 0) {
+ fprintf(stderr, "%s: fatal: fstat on %s ", self, in_filename);
+ perror("failed");
+ return;
+ }
+
+ if(compsize > (s.st_size - pos)) {
+ fatal = !(opts.force || opts.listonly);
+ fprintf(stderr, "%s: %s: compressed size for header #%d is bigger than the rest of the file (truncated?), use -F to override.\n", fatal ? "fatal" : "warning", self, headers_read);
+ exit(1);
+ }
+
+ if(compsize > origsize * 2) {
+ fatal = !(opts.force || opts.listonly);
+ fprintf(stderr, "%s: %s: compressed size for header #%d is over twice the uncompressed size (corrupt?), use -F to override.\n", fatal ? "fatal": "warning", self, headers_read);
+ exit(1);
+ }
}
/* return 1 if a header is read, 0 if not */
@@ -84,7 +114,7 @@ int read_alf_header(void) {
if(h2 < 0x0f) die_arc();
if(h2 == 0x0f) {
headers_read++;
- sanity_check_header();
+ sanity_check_header(read_pos);
return 1; /* signature matches */
}
}