From 07d1fdcc2f01ac63256e56db3a847e5cc4d8f8f8 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 14 Sep 2022 19:29:11 +0200 Subject: [PATCH] [cmp] update Bled to latest * Also try to fix the fallthrough Coverity warning in format_ext.c --- src/bled/bb_archive.h | 81 +++++++++----- src/bled/bled.c | 4 - src/bled/data_extract_all.c | 166 +++++++++++++++++---------- src/bled/decompress_bunzip2.c | 162 ++++++++++++++++++--------- src/bled/decompress_gunzip.c | 185 ++++++++++++++++++------------- src/bled/decompress_uncompress.c | 17 ++- src/bled/decompress_unlzma.c | 92 ++++++++++++--- src/bled/decompress_unzip.c | 1 + src/bled/header_verbose_list.c | 6 +- src/bled/libbb.h | 9 +- src/bled/open_transformer.c | 2 +- src/bled/xz_dec_lzma2.c | 10 +- src/bled/xz_dec_stream.c | 4 +- src/format_ext.c | 3 + src/rufus.rc | 10 +- 15 files changed, 485 insertions(+), 267 deletions(-) diff --git a/src/bled/bb_archive.h b/src/bled/bb_archive.h index 0a3c8287..fc58dc5f 100644 --- a/src/bled/bb_archive.h +++ b/src/bled/bb_archive.h @@ -64,6 +64,9 @@ typedef struct archive_handle_t { /* Currently processed file's header */ file_header_t *file_header; + /* List of link placeholders */ + llist_t *link_placeholders; + /* Process the header component, e.g. tar -t */ void FAST_FUNC (*action_header)(const file_header_t *); @@ -77,6 +80,9 @@ typedef struct archive_handle_t { off_t offset; /* Archiver specific. Can make it a union if it ever gets big */ +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + unsigned tar__strip_components; +#endif #define PAX_NEXT_FILE 0 #define PAX_GLOBAL 1 #if ENABLE_TAR || ENABLE_DPKG || ENABLE_DPKG_DEB @@ -95,6 +101,7 @@ typedef struct archive_handle_t { #endif #if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM uoff_t cpio__blocks; + struct bb_uidgid_t cpio__owner; struct hardlinks_t *cpio__hardlinks_to_create; struct hardlinks_t *cpio__created_hardlinks; #endif @@ -110,20 +117,23 @@ typedef struct archive_handle_t { const char *ar__name; struct archive_handle_t *ar__out; #endif +#if ENABLE_FEATURE_AR_LONG_FILENAMES + char *ar__long_names; + unsigned ar__long_name_size; +#endif } archive_handle_t; /* bits in ah_flags */ #define ARCHIVE_RESTORE_DATE (1 << 0) #define ARCHIVE_CREATE_LEADING_DIRS (1 << 1) #define ARCHIVE_UNLINK_OLD (1 << 2) -#define ARCHIVE_EXTRACT_QUIET (1 << 3) -#define ARCHIVE_EXTRACT_NEWER (1 << 4) -#define ARCHIVE_DONT_RESTORE_OWNER (1 << 5) -#define ARCHIVE_DONT_RESTORE_PERM (1 << 6) -#define ARCHIVE_NUMERIC_OWNER (1 << 7) -#define ARCHIVE_O_TRUNC (1 << 8) -#define ARCHIVE_REMEMBER_NAMES (1 << 9) +#define ARCHIVE_EXTRACT_NEWER (1 << 3) +#define ARCHIVE_DONT_RESTORE_OWNER (1 << 4) +#define ARCHIVE_DONT_RESTORE_PERM (1 << 5) +#define ARCHIVE_NUMERIC_OWNER (1 << 6) +#define ARCHIVE_O_TRUNC (1 << 7) +#define ARCHIVE_REMEMBER_NAMES (1 << 8) #if ENABLE_RPM -#define ARCHIVE_REPLACE_VIA_RENAME (1 << 10) +#define ARCHIVE_REPLACE_VIA_RENAME (1 << 9) #endif @@ -157,6 +167,11 @@ typedef struct tar_header_t { /* byte offset */ struct BUG_tar_header { char c[sizeof(tar_header_t) == TAR_BLOCK_SIZE ? 1 : -1]; }; +void chksum_and_xwrite_tar_header(int fd, struct tar_header_t *hp) FAST_FUNC; + + +extern const char cpio_TRAILER[]; + archive_handle_t *init_handle(void) FAST_FUNC; @@ -188,41 +203,47 @@ void seek_by_jump(int fd, off_t amount) FAST_FUNC; void seek_by_read(int fd, off_t amount) FAST_FUNC; const char *strip_unsafe_prefix(const char *str) FAST_FUNC; +void create_or_remember_link(llist_t **link_placeholders, + const char *target, + const char *linkname, + int hard_link) FAST_FUNC; +void create_links_from_list(llist_t *list) FAST_FUNC; void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC; const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_FUNC; const llist_t *find_list_entry2(const llist_t *list, const char *filename) FAST_FUNC; /* A bit of bunzip2 internals are exposed for compressed help support: */ -typedef struct bunzip_data bunzip_data; -int start_bunzip(bunzip_data **bdp, int in_fd, const void *inbuf, int len) FAST_FUNC; -/* NB: read_bunzip returns < 0 on error, or the number of *unfilled* bytes - * in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0: */ -int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; -void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; +char *unpack_bz2_data(const char *packed, int packed_len, int unpacked_len) FAST_FUNC; /* Meaning and direction (input/output) of the fields are transformer-specific */ typedef struct transformer_state_t { - int8_t check_signature; /* most often referenced member */ + int8_t signature_skipped; /* most often referenced member */ IF_DESKTOP(long long) int FAST_FUNC (*xformer)(struct transformer_state_t *xstate); USE_FOR_NOMMU(const char *xformer_prog;) /* Source */ - int src_fd; + int src_fd; /* Output */ - int dst_fd; - const char *dst_dir; /* if non-NULL, extract to dir */ - char *dst_name; - uint64_t dst_size; - size_t mem_output_size_max; /* if non-zero, decompress to RAM instead of fd */ - size_t mem_output_size; - char *mem_output_buf; + int dst_fd; + const char *dst_dir; /* if non-NULL, extract to dir */ + char *dst_name; + uint64_t dst_size; + size_t mem_output_size_max; /* if non-zero, decompress to RAM instead of fd */ + size_t mem_output_size; + char *mem_output_buf; - uint64_t bytes_out; - uint64_t bytes_in; /* used in unzip code only: needs to know packed size */ - uint32_t crc32; - time_t mtime; /* gunzip code may set this on exit */ + uint64_t bytes_out; + uint64_t bytes_in; /* used in unzip code only: needs to know packed size */ + uint32_t crc32; + time_t mtime; /* gunzip code may set this on exit */ + + union { /* if we read magic, it's saved here */ + uint8_t b[8]; + uint16_t b16[4]; + uint32_t b32[2]; + } magic; } transformer_state_t; void init_transformer_state(transformer_state_t *xstate) FAST_FUNC; @@ -278,11 +299,11 @@ int bbunpack(char **argv, void check_errors_in_children(int signo); #if BB_MMU void fork_transformer(int fd, - int check_signature, + int signature_skipped, IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate) ) FAST_FUNC; -#define fork_transformer_with_sig(fd, transformer, transform_prog) fork_transformer((fd), 1, (transformer)) -#define fork_transformer_with_no_sig(fd, transformer) fork_transformer((fd), 0, (transformer)) +#define fork_transformer_with_sig(fd, transformer, transform_prog) fork_transformer((fd), 0, (transformer)) +#define fork_transformer_with_no_sig(fd, transformer) fork_transformer((fd), 1, (transformer)) #else void fork_transformer(int fd, const char *transform_prog) FAST_FUNC; #define fork_transformer_with_sig(fd, transformer, transform_prog) fork_transformer((fd), (transform_prog)) diff --git a/src/bled/bled.c b/src/bled/bled.c index fbacae6e..28b87557 100644 --- a/src/bled/bled.c +++ b/src/bled/bled.c @@ -65,7 +65,6 @@ int64_t bled_uncompress(const char* src, const char* dst, int type) init_transformer_state(&xstate); xstate.src_fd = -1; xstate.dst_fd = -1; - xstate.check_signature = 1; xstate.src_fd = _openU(src, _O_RDONLY | _O_BINARY, 0); if (xstate.src_fd < 0) { @@ -113,7 +112,6 @@ int64_t bled_uncompress_with_handles(HANDLE hSrc, HANDLE hDst, int type) init_transformer_state(&xstate); xstate.src_fd = -1; xstate.dst_fd = -1; - xstate.check_signature = 1; xstate.src_fd = _open_osfhandle((intptr_t)hSrc, _O_RDONLY); if (xstate.src_fd < 0) { @@ -157,7 +155,6 @@ int64_t bled_uncompress_to_buffer(const char* src, char* buf, size_t size, int t init_transformer_state(&xstate); xstate.src_fd = -1; xstate.dst_fd = -1; - xstate.check_signature = 1; if (src[0] == 0) { xstate.src_fd = bb_virtual_fd; @@ -206,7 +203,6 @@ int64_t bled_uncompress_to_dir(const char* src, const char* dir, int type) init_transformer_state(&xstate); xstate.src_fd = -1; xstate.dst_fd = -1; - xstate.check_signature = 1; xstate.src_fd = _openU(src, _O_RDONLY | _O_BINARY, 0); if (xstate.src_fd < 0) { diff --git a/src/bled/data_extract_all.c b/src/bled/data_extract_all.c index 83adef4d..8820cf35 100644 --- a/src/bled/data_extract_all.c +++ b/src/bled/data_extract_all.c @@ -2,7 +2,6 @@ /* * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - #include "libbb.h" #include "bb_archive.h" @@ -11,6 +10,12 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) file_header_t *file_header = archive_handle->file_header; int dst_fd; int res; + char *hard_link; +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + char *dst_name; +#else +# define dst_name (file_header->name) +#endif #if ENABLE_FEATURE_TAR_SELINUX char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; @@ -23,11 +28,49 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) } #endif + /* Hard links are encoded as regular files of size 0 + * with a nonempty link field */ + hard_link = NULL; + if (S_ISREG(file_header->mode) && file_header->size == 0) + hard_link = file_header->link_target; + +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + dst_name = file_header->name; + if (archive_handle->tar__strip_components) { + unsigned n = archive_handle->tar__strip_components; + do { + dst_name = strchr(dst_name, '/'); + if (!dst_name || dst_name[1] == '\0') { + data_skip(archive_handle); + goto ret; + } + dst_name++; + /* + * Link target is shortened only for hardlinks: + * softlinks restored unchanged. + */ + if (hard_link) { +// GNU tar 1.26 does not check that we reached end of link name: +// if "dir/hardlink" is hardlinked to "file", +// tar xvf a.tar --strip-components=1 says: +// tar: hardlink: Cannot hard link to '': No such file or directory +// and continues processing. We silently skip such entries. + hard_link = strchr(hard_link, '/'); + if (!hard_link || hard_link[1] == '\0') { + data_skip(archive_handle); + goto ret; + } + hard_link++; + } + } while (--n != 0); + } +#endif + if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { - char *slash = strrchr(file_header->name, '/'); + char *slash = strrchr(dst_name, '/'); if (slash) { *slash = '\0'; - bb_make_directory(file_header->name, -1, FILEUTILS_RECUR); + bb_make_directory(dst_name, -1, FILEUTILS_RECUR); *slash = '/'; } } @@ -35,12 +78,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { /* Remove the entry if it exists */ if (!S_ISDIR(file_header->mode)) { - /* Is it hardlink? - * We encode hard links as regular files of size 0 with a symlink */ - if (S_ISREG(file_header->mode) - && file_header->link_target - && file_header->size == 0 - ) { + if (hard_link) { /* Ugly special case: * tar cf t.tar hardlink1 hardlink2 hardlink1 * results in this tarball structure: @@ -48,56 +86,46 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) * hardlink2 -> hardlink1 * hardlink1 -> hardlink1 <== !!! */ - if (strcmp(file_header->link_target, file_header->name) == 0) + if (strcmp(hard_link, dst_name) == 0) goto ret; } /* Proceed with deleting */ - if (_unlink(file_header->name) == -1 + if (_unlink(dst_name) == -1 && errno != ENOENT ) { bb_perror_msg_and_die("can't remove old file %s", - file_header->name); + dst_name); } } } else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { /* Remove the existing entry if its older than the extracted entry */ struct stat existing_sb; - if (lstat(file_header->name, &existing_sb) == -1) { + if (lstat(dst_name, &existing_sb) == -1) { if (errno != ENOENT) { - bb_perror_msg_and_die("can't stat old file"); + bb_simple_perror_msg_and_die("can't stat old file"); } } else if (existing_sb.st_mtime >= file_header->mtime) { - if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) - && !S_ISDIR(file_header->mode) - ) { + if (!S_ISDIR(file_header->mode)) { bb_error_msg("%s not created: newer or " - "same age file exists", file_header->name); + "same age file exists", dst_name); } data_skip(archive_handle); goto ret; } - else if ((_unlink(file_header->name) == -1) && (errno != EISDIR)) { + else if ((_unlink(dst_name) == -1) && (errno != EISDIR)) { bb_perror_msg_and_die("can't remove old file %s", - file_header->name); + dst_name); } } - /* Handle hard links separately - * We encode hard links as regular files of size 0 with a symlink */ - if (S_ISREG(file_header->mode) - && file_header->link_target - && file_header->size == 0 - ) { - /* hard link */ - res = link(file_header->link_target, file_header->name); - if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { - bb_perror_msg("can't create %slink " - "from %s to %s", "hard", - file_header->name, - file_header->link_target); - } + /* Handle hard links separately */ + if (hard_link) { + create_or_remember_link(&archive_handle->link_placeholders, + hard_link, + dst_name, + 1); /* Hardlinks have no separate mode/ownership, skip chown/chmod */ goto ret; } @@ -106,15 +134,17 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) switch (file_header->mode & S_IFMT) { case S_IFREG: { /* Regular file */ - char *dst_name; +#ifdef ARCHIVE_REPLACE_VIA_RENAME + char *dst_nameN; +#endif int flags = O_WRONLY | O_CREAT | O_EXCL; if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) flags = O_WRONLY | O_CREAT | O_TRUNC; - dst_name = file_header->name; #ifdef ARCHIVE_REPLACE_VIA_RENAME + dst_nameN = dst_name; if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) /* rpm-style temp file name */ - dst_name = xasprintf("%s;%x", dst_name, (int)getpid()); + dst_nameN = xasprintf("%s;%x", dst_name, (int)getpid()); #endif if (_sopen_s(&dst_fd, dst_name, flags, _SH_DENYNO, file_header->mode) != 0) { bb_perror_msg_and_die("can't open file %s", dst_name); @@ -123,48 +153,66 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) _close(dst_fd); #ifdef ARCHIVE_REPLACE_VIA_RENAME if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) { - xrename(dst_name, file_header->name); - free(dst_name); + xrename(dst_nameN, dst_name); + free(dst_nameN); } #endif break; } case S_IFDIR: - res = mkdir(file_header->name, file_header->mode); - if ((res == -1) +//TODO: this causes problems if tarball contains a r-xr-xr-x directory: +// we create this directory, and then fail to create files inside it +// (if tar xf isn't run as root). +// GNU tar works around this by chmod-ing directories *after* all files are extracted. + res = mkdir(dst_name, file_header->mode); + if ((res != 0) && (errno != EISDIR) /* btw, Linux doesn't return this */ && (errno != EEXIST) - && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { - bb_perror_msg("can't make dir %s", file_header->name); + bb_perror_msg("can't make dir %s", dst_name); } break; case S_IFLNK: /* Symlink */ //TODO: what if file_header->link_target == NULL (say, corrupted tarball?) - res = symlink(file_header->link_target, file_header->name); - if ((res == -1) - && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) - ) { - bb_perror_msg("can't create %slink " - "from %s to %s", "sym", - file_header->name, - file_header->link_target); - } + + /* To avoid a directory traversal attack via symlinks, + * do not restore symlinks with ".." components + * or symlinks starting with "/", unless a magic + * envvar is set. + * + * For example, consider a .tar created via: + * $ tar cvf bug.tar anything.txt + * $ ln -s /tmp symlink + * $ tar --append -f bug.tar symlink + * $ rm symlink + * $ mkdir symlink + * $ tar --append -f bug.tar symlink/evil.py + * + * This will result in an archive that contains: + * $ tar --list -f bug.tar + * anything.txt + * symlink [-> /tmp] + * symlink/evil.py + * + * Untarring bug.tar would otherwise place evil.py in '/tmp'. + */ + create_or_remember_link(&archive_handle->link_placeholders, + file_header->link_target, + dst_name, + 0); break; case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: - res = mknod(file_header->name, file_header->mode, file_header->device); - if ((res == -1) - && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) - ) { - bb_perror_msg("can't create node %s", file_header->name); + res = mknod(dst_name, file_header->mode, file_header->device); + if (res != 0) { + bb_perror_msg("can't create node %s", dst_name); } break; default: - bb_error_msg_and_die("unrecognized file type"); + bb_simple_error_msg_and_die("unrecognized file type"); } if (!S_ISLNK(file_header->mode)) { @@ -199,7 +247,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) t[1].tv_sec = t[0].tv_sec = file_header->mtime; t[1].tv_usec = t[0].tv_usec = 0; - utimes64(file_header->name, t); + utimes64(dst_name, t); } } diff --git a/src/bled/decompress_bunzip2.c b/src/bled/decompress_bunzip2.c index 8facca53..0f7a554f 100644 --- a/src/bled/decompress_bunzip2.c +++ b/src/bled/decompress_bunzip2.c @@ -1,14 +1,14 @@ /* vi: set sw=4 ts=4: */ -/* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net). - - Based on bzip2 decompression code by Julian R Seward (jseward@acm.org), - which also acknowledges contributions by Mike Burrows, David Wheeler, - Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten, - Robert Sedgewick, and Jon L. Bentley. - - Licensed under GPLv2 or later, see file LICENSE in this source tree. -*/ - +/* + * Small bzip2 deflate implementation, by Rob Landley (rob@landley.net). + * + * Based on bzip2 decompression code by Julian R Seward (jseward@acm.org), + * which also acknowledges contributions by Mike Burrows, David Wheeler, + * Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten, + * Robert Sedgewick, and Jon L. Bentley. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ /* Size and speed optimizations by Manuel Novoa III (mjn3@codepoet.org). @@ -38,7 +38,6 @@ Manuel */ - #include "libbb.h" #include "bb_archive.h" @@ -101,14 +100,14 @@ struct bunzip_data { unsigned dbufSize; /* For I/O error handling */ - jmp_buf jmpbuf; + jmp_buf *jmpbuf; /* Big things go last (register-relative addressing can be larger for big offsets) */ uint32_t crc32Table[256]; uint8_t selectors[32768]; /* nSelectors=15 bits */ struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */ }; -/* typedef struct bunzip_data bunzip_data; -- done in .h file */ +typedef struct bunzip_data bunzip_data; /* Return the next nnn bits of input. All reads from the compressed input @@ -128,14 +127,15 @@ static unsigned get_bits(bunzip_data *bd, int bits_wanted) /* if "no input fd" case: in_fd == -1, read fails, we jump */ bd->inbufCount = safe_read(bd->in_fd, bd->inbuf, IOBUF_SIZE); if (bd->inbufCount <= 0) - longjmp(bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF); + longjmp(*bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF); bd->inbufPos = 0; } /* Avoid 32-bit overflow (dump bit buffer to top of output) */ if (bit_count >= 24) { - bits = bd->inbufBits & ((1 << bit_count) - 1); + bits = bd->inbufBits & ((1U << bit_count) - 1); bits_wanted -= bit_count; + // coverity[negative_shift] bits <<= bits_wanted; bit_count = 0; } @@ -152,20 +152,20 @@ static unsigned get_bits(bunzip_data *bd, int bits_wanted) return bits; } +//#define get_bits(bd, n) (dbg("%d:get_bits()", __LINE__), get_bits(bd, n)) /* Unpacks the next block and sets up for the inverse Burrows-Wheeler step. */ static int get_next_block(bunzip_data *bd) { - struct group_data *hufGroup; - int dbufCount, dbufSize, groupCount, *base, *limit, selector, - i, j, t, runPos, symCount, symTotal, nSelectors, byteCount[256]; - int runCnt; + int groupCount, selector, + i, j, symCount, symTotal, nSelectors, byteCount[256]; uint8_t uc, symToByte[256], mtfSymbol[256], *selectors; uint32_t *dbuf; - unsigned origPtr; + unsigned origPtr, t; + unsigned dbufCount, runPos; + unsigned runCnt = 0; // runCnt; /* for compiler */ dbuf = bd->dbuf; - dbufSize = bd->dbufSize; selectors = bd->selectors; /* In bbox, we are ok with aborting through setjmp which is set up in start_bunzip */ @@ -180,15 +180,19 @@ static int get_next_block(bunzip_data *bd) i = get_bits(bd, 24); j = get_bits(bd, 24); bd->headerCRC = get_bits(bd, 32); - if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK; - if ((i != 0x314159) || (j != 0x265359)) return RETVAL_NOT_BZIP_DATA; + if ((i == 0x177245) && (j == 0x385090)) + return RETVAL_LAST_BLOCK; + if ((i != 0x314159) || (j != 0x265359)) + return RETVAL_NOT_BZIP_DATA; /* We can add support for blockRandomised if anybody complains. There was some code for this in busybox 1.0.0-pre3, but nobody ever noticed that it didn't actually work. */ - if (get_bits(bd, 1)) return RETVAL_OBSOLETE_INPUT; + if (get_bits(bd, 1)) + return RETVAL_OBSOLETE_INPUT; origPtr = get_bits(bd, 24); - if ((int)origPtr > dbufSize) return RETVAL_DATA_ERROR; + if (origPtr > bd->dbufSize) + return RETVAL_DATA_ERROR; /* mapping table: if some byte values are never used (encoding things like ascii text), the compression code removes the gaps to have fewer @@ -232,8 +236,9 @@ static int get_next_block(bunzip_data *bd) /* Get next value */ int n = 0; while (get_bits(bd, 1)) { - if (n >= groupCount) return RETVAL_DATA_ERROR; n++; + if (n >= groupCount) + return RETVAL_DATA_ERROR; } /* Decode MTF to get the next selector */ tmp_byte = mtfSymbol[n]; @@ -249,6 +254,8 @@ static int get_next_block(bunzip_data *bd) uint8_t length[MAX_SYMBOLS]; /* 8 bits is ALMOST enough for temp[], see below */ unsigned temp[MAX_HUFCODE_BITS+1]; + struct group_data *hufGroup; + int *base, *limit; int minLen, maxLen, pp, len_m1; /* Read Huffman code lengths for each symbol. They're stored in @@ -284,8 +291,10 @@ static int get_next_block(bunzip_data *bd) /* Find largest and smallest lengths in this group */ minLen = maxLen = length[0]; for (i = 1; i < symCount; i++) { - if (length[i] > maxLen) maxLen = length[i]; - else if (length[i] < minLen) minLen = length[i]; + if (length[i] > maxLen) + maxLen = length[i]; + else if (length[i] < minLen) + minLen = length[i]; } /* Calculate permute[], base[], and limit[] tables from length[]. @@ -308,7 +317,7 @@ static int get_next_block(bunzip_data *bd) base = hufGroup->base - 1; limit = hufGroup->limit - 1; - /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */ + /* Calculate permute[]. Concurrently, initialize temp[] and limit[]. */ pp = 0; for (i = minLen; i <= maxLen; i++) { int k; @@ -321,7 +330,8 @@ static int get_next_block(bunzip_data *bd) /* Count symbols coded for at each bit length */ /* NB: in pathological cases, temp[8] can end ip being 256. * That's why uint8_t is too small for temp[]. */ - for (i = 0; i < symCount; i++) temp[length[i]]++; + for (i = 0; i < symCount; i++) + temp[length[i]]++; /* Calculate limit[] (the largest symbol-coding value at each bit * length, which is (previous limit<<1)+symbols at this level), and @@ -364,12 +374,22 @@ static int get_next_block(bunzip_data *bd) runPos = dbufCount = selector = 0; for (;;) { + struct group_data *hufGroup; + int *base, *limit; int nextSym; + uint8_t ngrp; /* Fetch next Huffman coding group from list. */ symCount = GROUP_SIZE - 1; - if (selector >= nSelectors) return RETVAL_DATA_ERROR; - hufGroup = bd->groups + selectors[selector++]; + if (selector >= nSelectors) + return RETVAL_DATA_ERROR; + ngrp = selectors[selector++]; + if (ngrp >= groupCount) { + dbg("%d selectors[%d]:%d groupCount:%d", + __LINE__, selector-1, ngrp, groupCount); + return RETVAL_DATA_ERROR; + } + hufGroup = bd->groups + ngrp; base = hufGroup->base - 1; limit = hufGroup->limit - 1; @@ -404,7 +424,8 @@ static int get_next_block(bunzip_data *bd) } /* Figure how many bits are in next symbol and unget extras */ i = hufGroup->minLen; - while (nextSym > limit[i]) ++i; + while (nextSym > limit[i]) + ++i; j = hufGroup->maxLen - i; if (j < 0) return RETVAL_DATA_ERROR; @@ -436,7 +457,7 @@ static int get_next_block(bunzip_data *bd) symbols, but a run of length 0 doesn't mean anything in this context). Thus space is saved. */ runCnt += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ - if (runPos < dbufSize) runPos <<= 1; + if (runPos < bd->dbufSize) runPos <<= 1; goto end_of_huffman_loop; } @@ -446,14 +467,15 @@ static int get_next_block(bunzip_data *bd) literal used is the one at the head of the mtfSymbol array.) */ if (runPos != 0) { uint8_t tmp_byte; - if (dbufCount + runCnt > dbufSize) { - dbg("dbufCount:%d+runCnt:%d %d > dbufSize:%d RETVAL_DATA_ERROR", - dbufCount, runCnt, dbufCount + runCnt, dbufSize); + if (dbufCount + runCnt > bd->dbufSize) { + dbg("dbufCount:%u+runCnt:%u %u > dbufSize:%u RETVAL_DATA_ERROR", + dbufCount, runCnt, dbufCount + runCnt, bd->dbufSize); return RETVAL_DATA_ERROR; } tmp_byte = symToByte[mtfSymbol[0]]; byteCount[tmp_byte] += runCnt; - while (--runCnt >= 0) dbuf[dbufCount++] = (uint32_t)tmp_byte; + while ((int)--runCnt >= 0) + dbuf[dbufCount++] = (uint32_t)tmp_byte; runPos = 0; } @@ -467,7 +489,7 @@ static int get_next_block(bunzip_data *bd) first symbol in the mtf array, position 0, would have been handled as part of a run above. Therefore 1 unused mtf position minus 2 non-literal nextSym values equals -1.) */ - if (dbufCount >= dbufSize) return RETVAL_DATA_ERROR; + if (dbufCount >= bd->dbufSize) return RETVAL_DATA_ERROR; i = nextSym - 1; uc = mtfSymbol[i]; @@ -507,7 +529,7 @@ static int get_next_block(bunzip_data *bd) } /* Figure out what order dbuf would be in if we sorted it. */ - for (i = 0; i < dbufCount; i++) { + for (i = 0; i < (int)dbufCount; i++) { uint8_t tmp_byte = (uint8_t)dbuf[i]; int tmp_count = byteCount[tmp_byte]; dbuf[tmp_count] |= (i << 8); @@ -540,7 +562,7 @@ static int get_next_block(bunzip_data *bd) in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0. (Why? This allows to get rid of one local variable) */ -int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) +static int read_bunzip(bunzip_data *bd, char *outbuf, int len) { const uint32_t *dbuf; int pos, current, previous; @@ -619,7 +641,7 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) /* Subtract the 1 copy we'd output anyway to get extras */ --bd->writeCopies; } - } /* for(;;) */ + } /* for (;;) */ /* Decompression of this input block completed successfully */ bd->writeCRC = CRC = ~CRC; @@ -664,7 +686,10 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) /* Because bunzip2 is used for help text unpacking, and because bb_show_usage() should work for NOFORK applets too, we must be extremely careful to not leak any allocations! */ -int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, +static int FAST_FUNC start_bunzip( + void *jmpbuf, + bunzip_data **bdp, + int in_fd, const void *inbuf, int len) { bunzip_data *bd; @@ -676,13 +701,16 @@ int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, /* Figure out how much data to allocate */ i = sizeof(bunzip_data); - if (in_fd != -1) i += IOBUF_SIZE; + if (in_fd != -1) + i += IOBUF_SIZE; /* Allocate bunzip_data. Most fields initialize to zero. */ bd = *bdp = xzalloc(i); if (bd == NULL) return -1; + bd->jmpbuf = jmpbuf; + /* Setup input buffer */ bd->in_fd = in_fd; if (-1 == in_fd) { @@ -697,10 +725,6 @@ int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, /* Init the CRC32 table (big endian) */ crc32_filltable(bd->crc32Table, 1); - /* Setup for I/O error handling via longjmp */ - i = setjmp(bd->jmpbuf); - if (i) return i; - /* Ensure that file starts with "BZh['1'-'9']." */ /* Update: now caller verifies 1st two bytes, makes .gz/.bz2 * integration easier */ @@ -724,7 +748,7 @@ int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, return RETVAL_OK; } -void FAST_FUNC dealloc_bunzip(bunzip_data *bd) +static void FAST_FUNC dealloc_bunzip(bunzip_data *bd) { free(bd->dbuf); free(bd); @@ -749,8 +773,12 @@ unpack_bz2_stream(transformer_state_t *xstate) return -1; len = 0; while (1) { /* "Process one BZ... stream" loop */ + jmp_buf jmpbuf; - i = start_bunzip(&bd, xstate->src_fd, outbuf + 2, len); + /* Setup for I/O error handling via longjmp */ + i = setjmp(jmpbuf); + if (i == 0) + i = start_bunzip(&jmpbuf, &bd, xstate->src_fd, outbuf + 2, len); if (i == 0) { while (1) { /* "Produce some output bytes" loop */ @@ -773,7 +801,7 @@ unpack_bz2_stream(transformer_state_t *xstate) /* Observed case when i == RETVAL_OK: * "bzcat z.bz2", where "z.bz2" is a bzipped zero-length file * (to be exact, z.bz2 is exactly these 14 bytes: - * 42 5a 68 39 17 72 45 38 50 90 00 00 00 00). + * 42 5a 68 39 17 72 45 38 50 90 00 00 00 00). */ && i != RETVAL_OK ) { @@ -781,7 +809,7 @@ unpack_bz2_stream(transformer_state_t *xstate) break; } if (bd->headerCRC != bd->totalCRC) { - bb_error_msg("CRC error"); + bb_simple_error_msg("CRC error"); break; } @@ -811,6 +839,36 @@ unpack_bz2_stream(transformer_state_t *xstate) return i ? i : IF_DESKTOP(total_written) + 0; } +char* FAST_FUNC +unpack_bz2_data(const char *packed, int packed_len, int unpacked_len) +{ + char *outbuf = NULL; + bunzip_data *bd; + int i; + jmp_buf jmpbuf; + + /* Setup for I/O error handling via longjmp */ + i = setjmp(jmpbuf); + if (i == 0) { + i = start_bunzip(&jmpbuf, + &bd, + /* src_fd: */ -1, + /* inbuf: */ packed, + /* len: */ packed_len + ); + } + /* read_bunzip can longjmp and end up here with i != 0 + * on read data errors! Not trivial */ + if (i == 0) { + /* Cannot use xmalloc: will leak bd in NOFORK case! */ + outbuf = malloc_or_warn(unpacked_len); + if (outbuf) + read_bunzip(bd, outbuf, unpacked_len); + } + dealloc_bunzip(bd); + return outbuf; +} + #ifdef TESTING static char *const bunzip_errors[] = { diff --git a/src/bled/decompress_gunzip.c b/src/bled/decompress_gunzip.c index 59f088e9..c2eda288 100644 --- a/src/bled/decompress_gunzip.c +++ b/src/bled/decompress_gunzip.c @@ -32,8 +32,6 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - -#include #include "libbb.h" #include "bb_archive.h" @@ -41,7 +39,8 @@ typedef struct huft_t { unsigned char e; /* number of extra bits or operation */ unsigned char b; /* number of bits in this code or subcode */ union { - unsigned short n; /* literal, length base, or distance base */ + unsigned n; /* literal, length base, or distance base */ + /* ^^^^^ was "unsigned short", but that results in larger code */ struct huft_t *t; /* pointer to next level of table */ } v; } huft_t; @@ -128,6 +127,8 @@ typedef struct state_t { #define gunzip_bb (S()gunzip_bb ) #define gunzip_bk (S()gunzip_bk ) #define to_read (S()to_read ) +// #define bytebuffer_max (S()bytebuffer_max ) +// Both gunzip and unzip can use constant buffer size now (16k): #define bytebuffer_max BB_BUFSIZE #define bytebuffer (S()bytebuffer ) #define bytebuffer_offset (S()bytebuffer_offset ) @@ -184,29 +185,26 @@ static const uint16_t mask_bits[] ALIGN2 = { 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; -/* Copy lengths for literal codes 257..285 */ -static const uint16_t cplens[] ALIGN2 = { - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, - 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 +/* Put lengths/offsets and extra bits in a struct of arrays + * to make calls to huft_build() have one fewer parameter. + */ +struct cp_ext { + uint16_t cp[31]; + uint8_t ext[31]; }; - +/* Copy lengths and extra bits for literal codes 257..285 */ /* note: see note #13 above about the 258 in this list. */ -/* Extra bits for literal codes 257..285 */ -static const uint8_t cplext[] ALIGN1 = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, - 5, 5, 5, 0, 99, 99 -}; /* 99 == invalid */ - -/* Copy offsets for distance codes 0..29 */ -static const uint16_t cpdist[] ALIGN2 = { - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, - 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 +static const struct cp_ext lit ALIGN2 = { + /*257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 */ + /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 */ + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 } /* 99 == invalid */ }; - -/* Extra bits for distance codes */ -static const uint8_t cpdext[] ALIGN1 = { - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, - 11, 11, 12, 12, 13, 13 +/* Copy offsets and extra bits for distance codes 0..29 */ +static const struct cp_ext dist ALIGN2 = { + /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 */ + { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 }, + { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 } }; /* Tables for deflate from PKZIP's appnote.txt. */ @@ -222,10 +220,19 @@ static const uint8_t border[] ALIGN1 = { * each table. * t: table to free */ +#define BAD_HUFT(p) ((uintptr_t)(p) & 1) +#define ERR_RET ((huft_t*)(uintptr_t)1) static void huft_free(huft_t *p) { huft_t *q; + /* + * If 'p' has the error bit set we have to clear it, otherwise we might run + * into a segmentation fault or an invalid pointer to free(p) + */ + //if (BAD_HUFT(p)) // commented out, since bit clearing has effect only if condition is true + p = (huft_t*)((uintptr_t)p & ~(uintptr_t)ERR_RET); + /* Go through linked list, freeing from the malloced (t[-1]) address. */ while (p) { q = (--p)->v.t; @@ -277,22 +284,23 @@ static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current /* Given a list of code lengths and a maximum table size, make a set of - * tables to decode that set of codes. Return zero on success, one if - * the given code set is incomplete (the tables are still built in this - * case), two if the input is invalid (all zero length codes or an - * oversubscribed set of lengths) - in this case stores NULL in *t. + * tables to decode that set of codes. * * b: code lengths in bits (all assumed <= BMAX) * n: number of codes (assumed <= N_MAX) * s: number of simple-valued codes (0..s-1) - * d: list of base values for non-simple codes - * e: list of extra bits for non-simple codes - * t: result: starting table + * cp_ext->cp,ext: list of base values/extra bits for non-simple codes * m: maximum lookup bits, returns actual + * result: starting table + * + * On error, returns a value with lowest-bit set on error. + * It can be just the value of 0x1, + * or a valid pointer to a Huffman table, ORed with 0x1 if incompete table + * is given: "fixed inflate" decoder feeds us such data. */ -static int huft_build(const unsigned *b, const unsigned n, - const unsigned s, const unsigned short *d, - const unsigned char *e, huft_t **t, unsigned *m) +static huft_t* huft_build(const unsigned *b, const unsigned n, + const unsigned s, const struct cp_ext *cp_ext, + unsigned *m) { unsigned a; /* counter for codes of length k */ unsigned c[BMAX + 1]; /* bit length count table */ @@ -303,34 +311,42 @@ static int huft_build(const unsigned *b, const unsigned n, unsigned i; /* counter, current code */ unsigned j; /* counter */ int k; /* number of bits in current code */ - unsigned *p; /* pointer into c[], b[], or v[] */ + const unsigned *p; /* pointer into c[], b[], or v[] */ huft_t *q; /* points to current table */ huft_t r; /* table entry for structure assignment */ huft_t *u[BMAX]; /* table stack */ - unsigned v[N_MAX]; /* values in order of bit length */ + unsigned v[N_MAX + 1]; /* values in order of bit length. last v[] is never used */ int ws[BMAX + 1]; /* bits decoded stack */ int w; /* bits decoded */ unsigned x[BMAX + 1]; /* bit offsets, then code stack */ unsigned *xp; /* pointer into x */ int y; /* number of dummy codes added */ unsigned z; /* number of entries in current table */ + huft_t *result; + huft_t **t; /* Length of EOB code, if any */ eob_len = n > 256 ? b[256] : BMAX; - *t = NULL; + memset(&r, 0, sizeof(r)); /* Generate counts for each bit length */ memset(c, 0, sizeof(c)); - p = (unsigned *) b; /* cast allows us to reuse p for pointing to b */ + p = b; i = n; do { c[*p]++; /* assume all entries <= BMAX */ p++; /* can't combine with above line (Solaris bug) */ } while (--i); if (c[0] == n) { /* null input - all zero length codes */ - *m = 0; - return 2; + q = xzalloc(3 * sizeof(*q)); + //q[0].v.t = NULL; + q[1].e = 99; /* invalid code marker */ + q[1].b = 1; + q[2].e = 99; /* invalid code marker */ + q[2].b = 1; + *m = 1; + return q + 1; } /* Find minimum and maximum length, bound *m by those */ @@ -346,11 +362,11 @@ static int huft_build(const unsigned *b, const unsigned n, for (y = 1 << j; j < i; j++, y <<= 1) { y -= c[j]; if (y < 0) - return 2; /* bad input: more codes than bits */ + return ERR_RET; /* bad input: more codes than bits */ } y -= c[i]; if (y < 0) - return 2; + return ERR_RET; c[i] += y; /* Generate starting offsets into the value table for each length */ @@ -362,8 +378,12 @@ static int huft_build(const unsigned *b, const unsigned n, *xp++ = j; } - /* Make a table of values in order of bit lengths */ - p = (unsigned *) b; + /* Make a table of values in order of bit lengths. + * To detect bad input, unused v[i]'s are set to invalid value UINT_MAX. + * In particular, last v[i] is never filled and must not be accessed. + */ + memset(v, 0xff, sizeof(v)); + p = b; i = 0; do { j = *p++; @@ -373,6 +393,8 @@ static int huft_build(const unsigned *b, const unsigned n, } while (++i < n); /* Generate the Huffman codes and for each, make the table entries */ + result = ERR_RET; + t = &result; x[0] = i = 0; /* first Huffman code is zero */ p = v; /* grab values in bit order */ htl = -1; /* no tables yet--level -1 */ @@ -430,14 +452,16 @@ static int huft_build(const unsigned *b, const unsigned n, /* set up table entry in r */ r.b = (unsigned char) (k - w); - if (p >= v + n) { + if (/*p >= v + n || -- redundant, caught by the second check: */ + *p == UINT_MAX /* do we access uninited v[i]? (see memset(v))*/ + ) { r.e = 99; /* out of values--invalid code */ } else if (*p < s) { r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB code */ r.v.n = (unsigned short) (*p++); /* simple code is just the value */ } else { - r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ - r.v.n = d[*p++ - s]; + r.e = (unsigned char) cp_ext->ext[*p - s]; /* non-simple--look up in lists */ + r.v.n = cp_ext->cp[*p++ - s]; } /* fill code-like entries with r */ @@ -462,8 +486,11 @@ static int huft_build(const unsigned *b, const unsigned n, /* return actual size of base table */ *m = ws[1]; - /* Return 1 if we were given an incomplete table */ - return y != 0 && g != 1; + if (y != 0 && g != 1) /* we were given an incomplete table */ + /* return "result" ORed with 1 */ + return (void*)((uintptr_t)result | 1); + + return result; } @@ -515,8 +542,9 @@ static NOINLINE int inflate_codes(STATE_PARAM_ONLY) e = t->e; if (e > 16) do { - if (e == 99) - abort_unzip(PASS_STATE_ONLY);; + if (e == 99) { + abort_unzip(PASS_STATE_ONLY); + } bb >>= t->b; k -= t->b; e -= 16; @@ -552,8 +580,9 @@ static NOINLINE int inflate_codes(STATE_PARAM_ONLY) e = t->e; if (e > 16) do { - if (e == 99) + if (e == 99) { abort_unzip(PASS_STATE_ONLY); + } bb >>= t->b; k -= t->b; e -= 16; @@ -762,14 +791,17 @@ static int inflate_block(STATE_PARAM smallint *e) for (; i < 288; i++) /* make a complete, but wrong code set */ ll[i] = 8; bl = 7; - huft_build(ll, 288, 257, cplens, cplext, &inflate_codes_tl, &bl); - /* huft_build() never return nonzero - we use known data */ + inflate_codes_tl = huft_build(ll, 288, 257, &lit, &bl); + /* ^^^ never returns error here - we use known data */ /* set up distance table */ for (i = 0; i < 30; i++) /* make an incomplete code set */ ll[i] = 5; bd = 5; - huft_build(ll, 30, 0, cpdist, cpdext, &inflate_codes_td, &bd); + inflate_codes_td = huft_build(ll, 30, 0, &dist, &bd); + /* ^^^ does return error here! (lsb bit is set) - we gave it incomplete code set */ + /* clearing error bit: */ + inflate_codes_td = (void*)((uintptr_t)inflate_codes_td & ~(uintptr_t)1); /* set up data for inflate_codes() */ inflate_codes_setup(PASS_STATE bl, bd); @@ -819,8 +851,9 @@ static int inflate_block(STATE_PARAM smallint *e) b_dynamic >>= 4; k_dynamic -= 4; - if (nl > 286 || nd > 30) + if (nl > 286 || nd > 30) { abort_unzip(PASS_STATE_ONLY); /* bad lengths */ + } /* read in bit-length-code lengths */ for (j = 0; j < nb; j++) { @@ -834,9 +867,9 @@ static int inflate_block(STATE_PARAM smallint *e) /* build decoding table for trees - single level, 7 bit lookup */ bl = 7; - i = huft_build(ll, 19, 19, NULL, NULL, &inflate_codes_tl, &bl); - if (i != 0) { - abort_unzip(PASS_STATE_ONLY); //return i; /* incomplete code set */ + inflate_codes_tl = huft_build(ll, 19, 19, NULL, &bl); + if (BAD_HUFT(inflate_codes_tl)) { + abort_unzip(PASS_STATE_ONLY); /* incomplete code set */ } /* read in literal and distance code lengths */ @@ -899,14 +932,15 @@ static int inflate_block(STATE_PARAM smallint *e) /* build the decoding tables for literal/length and distance codes */ bl = lbits; - - i = huft_build(ll, nl, 257, cplens, cplext, &inflate_codes_tl, &bl); - if (i != 0) + inflate_codes_tl = huft_build(ll, nl, 257, &lit, &bl); + if (BAD_HUFT(inflate_codes_tl)) { abort_unzip(PASS_STATE_ONLY); + } bd = dbits; - i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &inflate_codes_td, &bd); - if (i != 0) + inflate_codes_td = huft_build(ll + nl, nd, 0, &dist, &bd); + if (BAD_HUFT(inflate_codes_td)) { abort_unzip(PASS_STATE_ONLY); + } /* set up data for inflate_codes() */ inflate_codes_setup(PASS_STATE bl, bd); @@ -976,7 +1010,7 @@ inflate_unzip_internal(STATE_PARAM transformer_state_t *xstate) ssize_t nwrote; /* Allocate all global buffers (for DYN_ALLOC option) */ - gunzip_window = xmalloc(GUNZIP_WSIZE); + gunzip_window = xzalloc(GUNZIP_WSIZE); gunzip_outbuf_count = 0; gunzip_bytes_out = 0; gunzip_src_fd = xstate->src_fd; @@ -995,6 +1029,7 @@ inflate_unzip_internal(STATE_PARAM transformer_state_t *xstate) error_msg = "corrupted data"; if (setjmp(error_jmp)) { /* Error from deep inside zip machinery */ + bb_simple_error_msg("corrupted data"); n = -1; goto ret; } @@ -1070,7 +1105,7 @@ static int top_up(STATE_PARAM unsigned n) bytebuffer_offset = 0; bytebuffer_size = full_read(gunzip_src_fd, &bytebuffer[count], bytebuffer_max - count); if ((int)bytebuffer_size < 0) { - bb_error_msg(bb_msg_read_error); + bb_simple_error_msg(bb_msg_read_error); return 0; } bytebuffer_size += count; @@ -1122,9 +1157,8 @@ static int check_header_gzip(STATE_PARAM transformer_state_t *xstate) } PACKED formatted; } header; PRAGMA_END_PACKED - struct BUG_header { - char BUG_header[sizeof(header) == 8 ? 1 : -1]; - }; + + BUILD_BUG_ON(sizeof(header) != 8); /* * Rewind bytebuffer. We use the beginning because the header has 8 @@ -1165,6 +1199,7 @@ static int check_header_gzip(STATE_PARAM transformer_state_t *xstate) do { if (!top_up(PASS_STATE 1)) return 0; + // coverity[tainted_data] } while (bytebuffer[bytebuffer_offset++] != 0); if ((header.formatted.flags & 0x18) != 0x18) break; @@ -1194,16 +1229,16 @@ unpack_gz_stream(transformer_state_t *xstate) if (check_signature16(xstate, GZIP_MAGIC)) return -1; #else - if (xstate->check_signature) { + if (!xstate->signature_skipped) { uint16_t magic2; if (full_read(xstate->src_fd, &magic2, 2) != 2) { bad_magic: - bb_error_msg("invalid magic"); + bb_simple_error_msg("invalid magic"); return -1; } if (magic2 == COMPRESS_MAGIC) { - xstate->check_signature = 0; + xstate->signature_skipped = 2; return unpack_Z_stream(xstate); } if (magic2 != GZIP_MAGIC) @@ -1230,7 +1265,7 @@ unpack_gz_stream(transformer_state_t *xstate) again: if (!check_header_gzip(PASS_STATE xstate)) { - bb_error_msg("corrupted data"); + bb_simple_error_msg("corrupted data"); total = -1; goto ret; } @@ -1243,7 +1278,7 @@ unpack_gz_stream(transformer_state_t *xstate) total += n; if (!top_up(PASS_STATE 8)) { - bb_error_msg("corrupted data"); + bb_simple_error_msg("corrupted data"); total = -1; goto ret; } @@ -1251,7 +1286,7 @@ unpack_gz_stream(transformer_state_t *xstate) /* Validate decompression - crc */ v32 = buffer_read_le_u32(PASS_STATE_ONLY); if ((~gunzip_crc) != v32) { - bb_error_msg("crc error"); + bb_simple_error_msg("crc error"); total = -1; goto ret; } @@ -1259,7 +1294,7 @@ unpack_gz_stream(transformer_state_t *xstate) /* Validate decompression - size */ v32 = buffer_read_le_u32(PASS_STATE_ONLY); if ((uint32_t)gunzip_bytes_out != v32) { - bb_error_msg("incorrect length"); + bb_simple_error_msg("incorrect length"); total = -1; } diff --git a/src/bled/decompress_uncompress.c b/src/bled/decompress_uncompress.c index 6e00b302..df6cf263 100644 --- a/src/bled/decompress_uncompress.c +++ b/src/bled/decompress_uncompress.c @@ -1,10 +1,10 @@ /* vi: set sw=4 ts=4: */ -/* uncompress for busybox -- (c) 2002 Robert Griebl +/* + * uncompress for busybox -- (c) 2002 Robert Griebl * * based on the original compress42.c source * (see disclaimer below) */ - /* (N)compress42.c - File compression ala IEEE Computer, Mar 1992. * * Authors: @@ -21,9 +21,7 @@ * marc@suse.de : a small security fix for a buffer overflow * * [... History snipped ...] - * */ - #include "libbb.h" #include "bb_archive.h" @@ -115,7 +113,7 @@ unpack_Z_stream(transformer_state_t *xstate) /* xread isn't good here, we have to return - caller may want * to do some cleanup (e.g. delete incomplete unpacked file etc) */ if (full_read(xstate->src_fd, inbuf, 1) != 1) { - bb_error_msg("short read"); + bb_simple_error_msg("short read"); goto err; } @@ -168,7 +166,7 @@ unpack_Z_stream(transformer_state_t *xstate) if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) { rsize = safe_read(xstate->src_fd, inbuf + insize, IBUFSIZ); if (rsize < 0) - bb_error_msg_and_err(bb_msg_read_error); + bb_simple_error_msg_and_die(bb_msg_read_error); insize += rsize; } @@ -202,7 +200,7 @@ unpack_Z_stream(transformer_state_t *xstate) if (oldcode == -1) { if (code >= 256) - bb_error_msg_and_err("corrupted data"); /* %ld", code); */ + bb_simple_error_msg_and_die("corrupted data"); /* %ld", code); */ oldcode = code; finchar = (int) oldcode; outbuf[outpos++] = (unsigned char) finchar; @@ -238,7 +236,7 @@ unpack_Z_stream(transformer_state_t *xstate) insize, posbits, p[-1], p[0], p[1], p[2], p[3], (posbits & 07)); */ - bb_error_msg("corrupted data"); + bb_simple_error_msg("corrupted data"); goto err; } @@ -249,7 +247,7 @@ unpack_Z_stream(transformer_state_t *xstate) /* Generate output characters in reverse order */ while (code >= 256) { if (stackp <= &htabof(0)) - bb_error_msg_and_err("corrupted data"); + bb_simple_error_msg_and_die("corrupted data"); *--stackp = tab_suffixof(code); code = tab_prefixof(code); } @@ -301,7 +299,6 @@ unpack_Z_stream(transformer_state_t *xstate) /* Remember previous code. */ oldcode = incode; } - } while (rsize > 0); if (outpos > 0) { diff --git a/src/bled/decompress_unlzma.c b/src/bled/decompress_unlzma.c index 55e5d9ef..7eacf153 100644 --- a/src/bled/decompress_unlzma.c +++ b/src/bled/decompress_unlzma.c @@ -11,6 +11,13 @@ #include "libbb.h" #include "bb_archive.h" +#if 0 +# define dbg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg(...) ((void)0) +#endif + + #if ENABLE_FEATURE_LZMA_FAST # define speed_inline ALWAYS_INLINE # define size_inline @@ -52,7 +59,7 @@ static void rc_read(rc_t *rc) //TODO: return -1 instead //This will make unlzma delete broken unpacked file on unpack errors if (buffer_size <= 0) - bb_error_msg_and_die("unexpected EOF"); + bb_simple_error_msg_and_die("unexpected EOF"); rc->buffer_end = RC_BUFFER + buffer_size; rc->ptr = RC_BUFFER; } @@ -220,9 +227,10 @@ unpack_lzma_stream(transformer_state_t *xstate) rc_t *rc; int i; uint8_t *buffer; + uint32_t buffer_size; uint8_t previous_byte = 0; size_t buffer_pos = 0, global_pos = 0; - ssize_t nwrote; + ssize_t nwrote = 0; int len = 0; int state = 0; uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; @@ -230,7 +238,7 @@ unpack_lzma_stream(transformer_state_t *xstate) if (full_read(xstate->src_fd, &header, sizeof(header)) != sizeof(header) || header.pos >= (9 * 5 * 5) ) { - bb_error_msg("bad lzma header"); + bb_simple_error_msg("bad lzma header"); return -1; } @@ -250,7 +258,8 @@ unpack_lzma_stream(transformer_state_t *xstate) if (header.dict_size == 0) header.dict_size++; - buffer = xmalloc((size_t)MIN(header.dst_size, header.dict_size)); + buffer_size = (uint32_t)MIN(header.dst_size, header.dict_size); + buffer = xmalloc(buffer_size); { int num_probs; @@ -267,14 +276,14 @@ unpack_lzma_stream(transformer_state_t *xstate) while ((uint64_t)global_pos + buffer_pos < header.dst_size) { int pos_state = (buffer_pos + global_pos) & pos_state_mask; uintptr_t off1 = LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state; - uint16_t *prob1 = p + off1; + uint16_t *prob = p + off1; - if (!rc_is_bit_1(rc, prob1)) { + if (!rc_is_bit_1(rc, prob)) { static const char next_state[LZMA_NUM_STATES] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 }; int mi = 1; - prob1 = (p + LZMA_LITERAL + prob = (p + LZMA_LITERAL + (LZMA_LIT_SIZE * ((((buffer_pos + global_pos) & literal_pos_mask) << lc) + (previous_byte >> (8 - lc)) ) @@ -283,23 +292,27 @@ unpack_lzma_stream(transformer_state_t *xstate) if (state >= LZMA_NUM_LIT_STATES) { int match_byte; - uint32_t pos = (uint32_t)(buffer_pos - rep0); + uint32_t pos; - while (pos >= header.dict_size) + pos = (uint32_t)(buffer_pos - rep0); + if ((int32_t)pos < 0) { pos += header.dict_size; + if ((int32_t)pos < 0) + goto bad; + } match_byte = buffer[pos]; do { int bit; match_byte <<= 1; bit = match_byte & 0x100; - bit ^= (rc_get_bit(rc, prob1 + 0x100 + bit + mi, &mi) << 8); /* 0x100 or 0 */ + bit ^= (rc_get_bit(rc, prob + 0x100 + bit + mi, &mi) << 8); /* 0x100 or 0 */ if (bit) break; } while (mi < 0x100); } while (mi < 0x100) { - rc_get_bit(rc, prob1 + mi, &mi); + rc_get_bit(rc, prob + mi, &mi); } state = next_state[state]; @@ -336,14 +349,24 @@ unpack_lzma_stream(transformer_state_t *xstate) } else { prob2 += LZMA_IS_REP_G0 - LZMA_IS_REP; if (!rc_is_bit_1(rc, prob2)) { - uintptr_t off2 = LZMA_IS_REP_0_LONG + (state << LZMA_NUM_POS_BITS_MAX) + pos_state; - prob2 = p + off2; + prob2 = (p + LZMA_IS_REP_0_LONG + + (state << LZMA_NUM_POS_BITS_MAX) + + pos_state + ); if (!rc_is_bit_1(rc, prob2)) { #if ENABLE_FEATURE_LZMA_FAST - uint32_t pos = buffer_pos - rep0; + uint32_t pos; state = state < LZMA_NUM_LIT_STATES ? 9 : 11; - while (pos >= header.dict_size) + + pos = buffer_pos - rep0; + if ((int32_t)pos < 0) { pos += header.dict_size; + /* see unzip_bad_lzma_2.zip: */ + if (pos >= buffer_size) { + dbg("%d pos:%d buffer_size:%d", __LINE__, pos, buffer_size); + goto bad; + } + } previous_byte = buffer[pos]; goto one_byte1; #else @@ -418,6 +441,9 @@ unpack_lzma_stream(transformer_state_t *xstate) for (; num_bits2 != LZMA_NUM_ALIGN_BITS; num_bits2--) rep0 = (rep0 << 1) | rc_direct_bit(rc); rep0 <<= LZMA_NUM_ALIGN_BITS; + // Note: (int32_t)rep0 may be < 0 here + // (I have linux-3.3.4.tar.lzma which has it). + // I moved the check after "++rep0 == 0" check below. prob3 = p + LZMA_ALIGN; } i2 = 1; @@ -428,16 +454,43 @@ unpack_lzma_stream(transformer_state_t *xstate) i2 <<= 1; } } - if (++rep0 == 0) - break; + rep0++; + if ((int32_t)rep0 <= 0) { + if (rep0 == 0) + break; + dbg("%d rep0:%d", __LINE__, rep0); + goto bad; + } } len += LZMA_MATCH_MIN_LEN; + /* + * LZMA SDK has this optimized: + * it precalculates size and copies many bytes + * in a loop with simpler checks, a-la: + * do + * *(dest) = *(dest + ofs); + * while (++dest != lim); + * and + * do { + * buffer[buffer_pos++] = buffer[pos]; + * if (++pos == header.dict_size) + * pos = 0; + * } while (--cur_len != 0); + * Our code is slower (more checks per byte copy): + */ IF_NOT_FEATURE_LZMA_FAST(string:) do { uint32_t pos = (uint32_t)(buffer_pos - rep0); - while (pos >= header.dict_size) + if ((int32_t)pos < 0) { pos += header.dict_size; + /* bug 10436 has an example file where this triggers: */ + //if ((int32_t)pos < 0) + // goto bad; + /* more stringent test (see unzip_bad_lzma_1.zip): */ + if (pos >= buffer_size) + goto bad; + } previous_byte = buffer[pos]; IF_NOT_FEATURE_LZMA_FAST(one_byte2:) buffer[buffer_pos++] = previous_byte; @@ -453,6 +506,9 @@ unpack_lzma_stream(transformer_state_t *xstate) } while (len != 0 && buffer_pos < header.dst_size); /* FIXME: ...........^^^^^ * shouldn't it be "global_pos + buffer_pos < header.dst_size"? + * It probably should, but it is a "do we accidentally + * unpack more bytes than expected?" check - which + * never happens for well-formed compression data... */ } } diff --git a/src/bled/decompress_unzip.c b/src/bled/decompress_unzip.c index 8c8fcad4..1ab2fa83 100644 --- a/src/bled/decompress_unzip.c +++ b/src/bled/decompress_unzip.c @@ -312,6 +312,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_zip_stream(transformer_state_t *xstat xstate->dst_size = zip_header.formatted.ucmpsize; xstate->dst_name = xzalloc(zip_header.formatted.filename_len + 1); safe_read(xstate->src_fd, xstate->dst_name, zip_header.formatted.filename_len); + xstate->dst_name[zip_header.formatted.filename_len] = 0; n = transformer_switch_file(xstate); free(xstate->dst_name); if (n < 0) diff --git a/src/bled/header_verbose_list.c b/src/bled/header_verbose_list.c index 87dd8213..73e1fee4 100644 --- a/src/bled/header_verbose_list.c +++ b/src/bled/header_verbose_list.c @@ -2,7 +2,6 @@ /* * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - #include "libbb.h" #include "bb_archive.h" @@ -12,6 +11,7 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header) struct tm *ptm = &tm_time; //localtime(&file_header->mtime); #if ENABLE_FEATURE_TAR_UNAME_GNAME + char modestr[12]; char uid[sizeof(int)*3 + 2]; /*char gid[sizeof(int)*3 + 2];*/ char *user; @@ -30,7 +30,7 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header) group = utoa(file_header->gid); } printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", - bb_mode_string(file_header->mode), + bb_mode_string(modestr, file_header->mode), user, group, file_header->size, @@ -47,7 +47,7 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header) localtime_r(&file_header->mtime, ptm); printf("%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", - bb_mode_string(file_header->mode), + bb_mode_string(modestr, file_header->mode), (unsigned)file_header->uid, (unsigned)file_header->gid, file_header->size, diff --git a/src/bled/libbb.h b/src/bled/libbb.h index 8eaa75c9..a4d75017 100644 --- a/src/bled/libbb.h +++ b/src/bled/libbb.h @@ -52,7 +52,7 @@ #define IF_NOT_FEATURE_LZMA_FAST(x) x #define uoff_t unsigned off_t -#define OFF_FMT "I64" +#define OFF_FMT PRIi64 #ifndef _MODE_T_ #define _MODE_T_ @@ -86,6 +86,8 @@ typedef unsigned int uid_t; #define PATH_MAX MAX_PATH #endif +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) + #ifndef get_le64 #define get_le64(ptr) (*(const uint64_t *)(ptr)) #endif @@ -146,6 +148,9 @@ extern unsigned long* bled_cancel_request; #define bb_error_msg_and_err(...) do {bb_error_msg(__VA_ARGS__); goto err;} while(0) #define bb_perror_msg bb_error_msg #define bb_perror_msg_and_die bb_error_msg_and_die +#define bb_simple_error_msg bb_error_msg +#define bb_simple_perror_msg_and_die bb_error_msg_and_die +#define bb_simple_error_msg_and_die bb_error_msg_and_die #define bb_putchar putchar static inline void *xrealloc(void *ptr, size_t size) { @@ -157,7 +162,7 @@ static inline void *xrealloc(void *ptr, size_t size) { #define bb_msg_read_error "read error" #define bb_msg_write_error "write error" -#define bb_mode_string(mode) "[not implemented]" +#define bb_mode_string(str, mode) "[not implemented]" #define bb_copyfd_exact_size(fd1, fd2, size) bb_error_msg("Not implemented") #define bb_make_directory(path, mode, flags) SHCreateDirectoryExU(NULL, path, NULL) diff --git a/src/bled/open_transformer.c b/src/bled/open_transformer.c index 2bc62bfe..4e420c7e 100644 --- a/src/bled/open_transformer.c +++ b/src/bled/open_transformer.c @@ -13,7 +13,7 @@ void FAST_FUNC init_transformer_state(transformer_state_t *xstate) int FAST_FUNC check_signature16(transformer_state_t *xstate, unsigned magic16) { - if (xstate->check_signature) { + if (!xstate->signature_skipped) { uint16_t magic2; if (full_read(xstate->src_fd, &magic2, 2) != 2 || magic2 != magic16) { bb_error_msg("invalid magic"); diff --git a/src/bled/xz_dec_lzma2.c b/src/bled/xz_dec_lzma2.c index eac9970d..7d936a83 100644 --- a/src/bled/xz_dec_lzma2.c +++ b/src/bled/xz_dec_lzma2.c @@ -486,11 +486,11 @@ static __always_inline void XZ_FUNC rc_normalize(struct rc_dec *rc) } /* - * Decode one bit. In some versions, this function has been splitted in three + * Decode one bit. In some versions, this function has been split in three * functions so that the compiler is supposed to be able to more easily avoid * an extra branch. In this particular version of the LZMA decoder, this * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3 - * on x86). Using a non-splitted version results in nicer looking code too. + * on x86). Using a non-split version results in nicer looking code too. * * NOTE: This must return an int. Do not make it return a bool or the speed * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care, @@ -788,6 +788,7 @@ static void XZ_FUNC lzma_reset(struct xz_dec_lzma2 *s) */ probs = s->lzma.is_match[0]; for (i = 0; i < PROBS_TOTAL; ++i) + // coverity[overrun-local] probs[i] = RC_BIT_MODEL_TOTAL / 2; rc_reset(&s->rc); @@ -995,10 +996,8 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( s->lzma2.need_props = false; s->lzma2.next_sequence = SEQ_PROPERTIES; - } else if (s->lzma2.need_props) { return XZ_DATA_ERROR; - } else { s->lzma2.next_sequence = SEQ_LZMA_PREPARE; @@ -1044,6 +1043,7 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( return XZ_DATA_ERROR; s->lzma2.sequence = SEQ_LZMA_PREPARE; + // Fall through case SEQ_LZMA_PREPARE: if (s->lzma2.compressed < RC_INIT_BYTES) @@ -1054,6 +1054,7 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( s->lzma2.compressed -= RC_INIT_BYTES; s->lzma2.sequence = SEQ_LZMA_RUN; + // Fall through case SEQ_LZMA_RUN: /* @@ -1080,7 +1081,6 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( rc_reset(&s->rc); s->lzma2.sequence = SEQ_CONTROL; - } else if (b->out_pos == b->out_size || (b->in_pos == b->in_size && s->temp.size diff --git a/src/bled/xz_dec_stream.c b/src/bled/xz_dec_stream.c index bdcbf1ba..31158b4e 100644 --- a/src/bled/xz_dec_stream.c +++ b/src/bled/xz_dec_stream.c @@ -353,7 +353,6 @@ static enum xz_ret XZ_FUNC crc32_validate(struct xz_dec *s, struct xz_buf *b) return XZ_DATA_ERROR; s->pos += 8; - } while (s->pos < 32); s->crc32 = 0; @@ -546,7 +545,7 @@ static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s) return XZ_OK; } -static enum xz_ret XZ_FUNC dec_main(struct xz_dec *s, struct xz_buf *b) +static NOINLINE enum xz_ret XZ_FUNC dec_main(struct xz_dec *s, struct xz_buf *b) { enum xz_ret ret; @@ -753,7 +752,6 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b) b->in_pos = in_start; b->out_pos = out_start; } - } else if (ret == XZ_OK && in_start == b->in_pos && out_start == b->out_pos) { if (s->allow_buf_error) diff --git a/src/format_ext.c b/src/format_ext.c index ba381988..f5b854ac 100644 --- a/src/format_ext.c +++ b/src/format_ext.c @@ -468,8 +468,11 @@ BOOL FormatExtFs(DWORD DriveIndex, uint64_t PartitionOffset, DWORD BlockSize, LP ctime = UINT32_MAX; inode.i_mode = 0100644; inode.i_links_count = 1; + // coverity[store_truncates_time_t] inode.i_atime = (uint32_t)ctime; + // coverity[store_truncates_time_t] inode.i_ctime = (uint32_t)ctime; + // coverity[store_truncates_time_t] inode.i_mtime = (uint32_t)ctime; inode.i_size = fsize; diff --git a/src/rufus.rc b/src/rufus.rc index 96eec074..08dd85b9 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.21.1934" +CAPTION "Rufus 3.21.1935" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -395,8 +395,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,21,1934,0 - PRODUCTVERSION 3,21,1934,0 + FILEVERSION 3,21,1935,0 + PRODUCTVERSION 3,21,1935,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -414,13 +414,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.21.1934" + VALUE "FileVersion", "3.21.1935" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2022 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-3.21.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.21.1934" + VALUE "ProductVersion", "3.21.1935" END END BLOCK "VarFileInfo"