diff options
| author | B. Watson <urchlay@slackware.uk> | 2025-12-03 03:00:10 -0500 |
|---|---|---|
| committer | B. Watson <urchlay@slackware.uk> | 2025-12-03 03:00:10 -0500 |
| commit | fff0d9587f674e2b1f61ba693ef830862dc1241d (patch) | |
| tree | 20a9d4d1e9fb145f2c2d937a478aa220f16da728 /src/io.c | |
| parent | 939dab58d23272a68c16c625dbd14ff3f8f6c51b (diff) | |
| download | alftools-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.c | 48 |
1 files changed, 39 insertions, 9 deletions
@@ -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 */ } } |
