libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

commit f3397e43664392aa0f116f5de422b74fb820e3a3
parent e85307c7a13fc3348f0c0f3ab690186c60eaeaea
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed, 29 Jul 2026 11:06:16 +0200

fix integer underflow/overflow issues

Diffstat:
Msrc/main/extractor_datasource.c | 45++++++++++++++++++++++++++++++---------------
1 file changed, 30 insertions(+), 15 deletions(-)

diff --git a/src/main/extractor_datasource.c b/src/main/extractor_datasource.c @@ -355,12 +355,13 @@ bfds_seek (struct BufferedFileDataSource *bfds, LOG ("Invalid seek operation\n"); return -1; } - if (bfds->fsize < -pos) + /* -pos is undefined for INT64_MIN; negate in unsigned arithmetic. */ + if (bfds->fsize < (uint64_t) -(uint64_t) pos) { LOG ("Invalid seek operation\n"); return -1; } - pos = bfds->fsize + pos; + pos = (int64_t) (bfds->fsize + (uint64_t) pos); /* fall-through! */ case SEEK_SET: if (pos < 0) @@ -1052,19 +1053,33 @@ cfs_seek (struct CompressedFileSource *cfs, switch (whence) { case SEEK_CUR: - if (cfs->fpos + position < 0) + if (position < 0) { - /* underflow */ - LOG ("Invalid seek operation\n"); - return -1; + /* underflow; -position is undefined for INT64_MIN, so the + magnitude is taken in unsigned arithmetic */ + if ((uint64_t) cfs->fpos < (uint64_t) -(uint64_t) position) + { + LOG ("Invalid seek operation\n"); + return -1; + } } - if ( (-1 != cfs->uncompressed_size) && - (cfs->fpos + position > cfs->uncompressed_size) ) + else { - LOG ("Invalid seek operation\n"); - return -1; + /* the addition itself must not overflow, which it can whenever + the uncompressed size is still unknown */ + if (position > INT64_MAX - cfs->fpos) + { + LOG ("Invalid seek operation\n"); + return -1; + } + if ( (-1 != cfs->uncompressed_size) && + (cfs->fpos + position > cfs->uncompressed_size) ) + { + LOG ("Invalid seek operation\n"); + return -1; + } } - nposition = cfs->fpos + position; + nposition = (uint64_t) (cfs->fpos + position); break; case SEEK_END: ASSERT (-1 != cfs->uncompressed_size); @@ -1073,12 +1088,12 @@ cfs_seek (struct CompressedFileSource *cfs, LOG ("Invalid seek operation\n"); return -1; } - if (cfs->uncompressed_size < -position) + if ((uint64_t) cfs->uncompressed_size < (uint64_t) -(uint64_t) position) { LOG ("Invalid seek operation\n"); return -1; } - nposition = cfs->uncompressed_size + position; + nposition = (uint64_t) (cfs->uncompressed_size + position); break; case SEEK_SET: if (position < 0) @@ -1098,10 +1113,10 @@ cfs_seek (struct CompressedFileSource *cfs, LOG ("Invalid seek operation\n"); return -1; } - delta = nposition - cfs->fpos; + delta = (int64_t) (nposition - (uint64_t) cfs->fpos); if (delta < 0) { - if (cfs->result_pos >= -delta) + if ((uint64_t) cfs->result_pos >= (uint64_t) -(uint64_t) delta) { cfs->result_pos += delta; cfs->fpos += delta;