Merge pull request #3265 from stoeckmann/ckd_alloc

Check size arithmetic before memory allocations
This commit is contained in:
Dustin L. Howett authored and GitHub committed 2026-07-07 13:49:14 -05:00
commit 40a71c8382
11 files changed
+92 -61

No files matched your search

+3 -3
View File
@@ -41,6 +41,7 @@
#include "archive.h"
#include "archive_entry.h"
#include "archive_integer.h"
/*
* This is mostly a pretty straightforward hash table implementation.
@@ -387,7 +388,7 @@ insert_entry(struct archive_entry_linkresolver *res,
}
/* If the links cache is getting too full, enlarge the hash table. */
if (res->number_entries > res->number_buckets * 2)
if (res->number_entries / 2 > res->number_buckets)
grow_hash(res);
hash = (size_t)(archive_entry_dev(entry) ^ archive_entry_ino64(entry));
@@ -413,8 +414,7 @@ grow_hash(struct archive_entry_linkresolver *res)
size_t i, bucket;
/* Try to enlarge the bucket list. */
new_size = res->number_buckets * 2;
if (new_size < res->number_buckets)
if (archive_ckd_mul_size(&new_size, res->number_buckets, 2))
return;
new_buckets = calloc(new_size, sizeof(struct links_entry *));
+4 -5
View File
@@ -1490,16 +1490,16 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
/* Ensure the buffer is big enough. */
if (min > filter->buffer_size) {
size_t s, t;
size_t s;
char *p;
/* Double the buffer; watch for overflow. */
s = t = filter->buffer_size;
s = filter->buffer_size;
if (s == 0)
s = min;
while (s < min) {
t *= 2;
if (t <= s) { /* Integer overflow! */
if (archive_ckd_mul_size(&s, s, 2)) {
/* Integer overflow! */
archive_set_error(
&filter->archive->archive,
ENOMEM,
@@ -1510,7 +1510,6 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
*avail = ARCHIVE_FATAL;
return (NULL);
}
s = t;
}
/* Now s >= min, so allocate a new buffer. */
p = malloc(s);
@@ -45,6 +45,7 @@
#endif
#include "archive.h"
#include "archive_integer.h"
#if defined(_WIN32) && !defined(__CYGWIN__)
int
@@ -209,7 +210,8 @@ lookup_uname_helper(struct name_cache *cache, id_t id)
* we just double it and try again. Because the buffer
* is kept around in the cache object, we shouldn't
* have to do this very often. */
nbuff_size = cache->buff_size * 2;
if (archive_ckd_mul_size(&nbuff_size, cache->buff_size, 2))
break;
nbuff = realloc(cache->buff, nbuff_size);
if (nbuff == NULL)
break;
@@ -276,7 +278,8 @@ lookup_gname_helper(struct name_cache *cache, id_t id)
/* ERANGE means our buffer was too small, but POSIX
* doesn't tell us how big the buffer should be, so
* we just double it and try again. */
nbuff_size = cache->buff_size * 2;
if (archive_ckd_mul_size(&nbuff_size, cache->buff_size, 2))
break;
nbuff = realloc(cache->buff, nbuff_size);
if (nbuff == NULL)
break;
+8 -2
View File
@@ -37,10 +37,11 @@
#include <winioctl.h>
#include "archive.h"
#include "archive_string.h"
#include "archive_entry.h"
#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_disk_private.h"
#include "archive_string.h"
#include "archive_time_private.h"
#ifndef O_BINARY
@@ -2540,7 +2541,12 @@ setup_sparse_from_disk(struct archive_read_disk *a,
(DWORD)outranges_size, &retbytes, NULL);
if (ret == 0 && GetLastError() == ERROR_MORE_DATA) {
free(outranges);
outranges_size *= 2;
if (archive_ckd_mul_size(&outranges_size, outranges_size, 2)) {
archive_set_error(&a->archive, ENOMEM,
"Couldn't allocate memory");
exit_sts = ARCHIVE_FATAL;
goto exit_setup_sparse;
}
outranges = (FILE_ALLOCATED_RANGE_BUFFER *)
malloc(outranges_size);
if (outranges == NULL) {
@@ -47,6 +47,7 @@
#include "archive_endian.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_string.h"
@@ -314,8 +315,8 @@ struct file_info {
struct heap_queue {
struct file_info **files;
int allocated;
int used;
size_t allocated;
size_t used;
};
struct iso9660 {
@@ -337,8 +338,8 @@ struct iso9660 {
uint64_t offset;/* Offset of CE on disk. */
struct file_info *file;
} *reqs;
int cnt;
int allocated;
size_t cnt;
size_t allocated;
} read_ce_req;
int64_t previous_number;
@@ -2368,9 +2369,8 @@ register_CE(struct archive_read *a, int32_t location,
{
struct iso9660 *iso9660;
struct read_ce_queue *heap;
struct read_ce_req *p;
uint64_t offset, parent_offset;
int hole, parent;
size_t hole, parent;
iso9660 = (struct iso9660 *)(a->format->data);
offset = ((uint64_t)location) * (uint64_t)iso9660->logical_block_size;
@@ -2389,14 +2389,13 @@ register_CE(struct archive_read *a, int32_t location,
/* Expand our CE list as necessary. */
heap = &(iso9660->read_ce_req);
if (heap->cnt >= heap->allocated) {
int new_size;
struct read_ce_req *p;
size_t new_size;
if (heap->allocated < 16)
new_size = 16;
else
new_size = heap->allocated * 2;
/* Overflow might keep us from growing the list. */
if (new_size <= heap->allocated) {
else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {
/* Overflow keeps us from growing the list. */
archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
@@ -2438,7 +2437,7 @@ static void
next_CE(struct read_ce_queue *heap)
{
uint64_t a_offset, b_offset, c_offset;
int a, b, c;
size_t a, b, c;
struct read_ce_req tmp;
if (heap->cnt < 1)
@@ -3144,7 +3143,7 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap,
struct file_info *file, uint64_t key)
{
uint64_t file_key, parent_key;
int hole, parent;
size_t hole, parent;
/* Reserve 16 bits for possible key collisions (needed for linked items) */
/* For ISO files with more than 65535 entries, reordering will still occur */
@@ -3154,12 +3153,12 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap,
/* Expand our pending files list as necessary. */
if (heap->used >= heap->allocated) {
struct file_info **new_pending_files;
int new_size = heap->allocated * 2;
size_t new_size;
if (heap->allocated < 1024)
new_size = 1024;
/* Overflow might keep us from growing the list. */
if (new_size <= heap->allocated) {
else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {
/* Overflow keeps us from growing the list. */
archive_set_error(&a->archive,
ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
@@ -3186,7 +3185,7 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap,
*/
hole = heap->used++;
while (hole > 0) {
parent = (hole - 1)/2;
parent = (hole - 1) / 2;
parent_key = heap->files[parent]->key;
if (file_key >= parent_key) {
heap->files[hole] = file;
@@ -3205,7 +3204,7 @@ static struct file_info *
heap_get_entry(struct heap_queue *heap)
{
uint64_t a_key, b_key, c_key;
int a, b, c;
size_t a, b, c;
struct file_info *r, *tmp;
if (heap->used < 1)
+14 -8
View File
@@ -42,6 +42,7 @@
#include "archive_endian.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
#include "archive_integer.h"
#include "archive_ppmd7_private.h"
#include "archive_private.h"
#include "archive_read_private.h"
@@ -201,8 +202,8 @@ struct huffman_table_entry
struct huffman_code
{
struct huffman_tree_node *tree;
int numentries;
int numallocatedentries;
size_t numentries;
size_t numallocatedentries;
int minlength;
int maxlength;
int tablesize;
@@ -2823,11 +2824,16 @@ new_node(struct huffman_code *code)
{
void *new_tree;
if (code->numallocatedentries == code->numentries) {
int new_num_entries = 256;
if (code->numentries > 0) {
new_num_entries = code->numentries * 2;
}
new_tree = realloc(code->tree, new_num_entries * sizeof(*code->tree));
size_t size, new_num_entries;
if (code->numentries == 0)
new_num_entries = 256;
else if (archive_ckd_mul_size(&new_num_entries, code->numentries, 2)
|| new_num_entries > INT_MAX)
return -1;
if (archive_ckd_mul_size(&size, new_num_entries, sizeof(*code->tree)))
return -1;
new_tree = realloc(code->tree, size);
if (new_tree == NULL)
return (-1);
code->tree = (struct huffman_tree_node *)new_tree;
@@ -2868,7 +2874,7 @@ make_table_recurse(struct archive_read *a, struct huffman_code *code, int node,
"Huffman tree was not created");
return (ARCHIVE_FAILED);
}
if (node < 0 || node >= code->numentries)
if (node < 0 || (size_t)node >= code->numentries)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid location to Huffman tree specified");
+9 -11
View File
@@ -214,8 +214,8 @@ struct hdlink {
struct heap_queue {
struct xar_file **files;
int allocated;
int used;
size_t allocated;
size_t used;
};
enum xmlstatus {
@@ -957,7 +957,7 @@ xar_cleanup(struct archive_read *a)
{
struct xar *xar;
struct hdlink *hdlink;
int i;
size_t i;
int r;
xar = (struct xar *)(a->format->data);
@@ -1207,19 +1207,17 @@ heap_add_entry(struct archive_read *a,
struct heap_queue *heap, struct xar_file *file)
{
uint64_t file_id, parent_id;
int hole, parent;
size_t hole, parent;
/* Expand our pending files list as necessary. */
if (heap->used >= heap->allocated) {
struct xar_file **new_pending_files;
int new_size;
size_t new_size;
if (heap->allocated < 1024)
new_size = 1024;
else
new_size = heap->allocated * 2;
/* Overflow might keep us from growing the list. */
if (new_size <= heap->allocated) {
else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {
/* Overflow keeps us from growing the list. */
archive_set_error(&a->archive,
ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
@@ -1247,7 +1245,7 @@ heap_add_entry(struct archive_read *a,
*/
hole = heap->used++;
while (hole > 0) {
parent = (hole - 1)/2;
parent = (hole - 1) / 2;
parent_id = heap->files[parent]->id;
if (file_id >= parent_id) {
heap->files[hole] = file;
@@ -1266,7 +1264,7 @@ static struct xar_file *
heap_get_entry(struct heap_queue *heap)
{
uint64_t a_id, b_id, c_id;
int a, b, c;
size_t a, b, c;
struct xar_file *r, *tmp;
if (heap->used < 1)
@@ -45,6 +45,7 @@
#endif
#include "archive.h"
#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_write_disk_private.h"
@@ -134,7 +135,8 @@ lookup_gid(void *private_data, const char *gname, int64_t gid)
break;
if (r != ERANGE)
break;
bufsize *= 2;
if (archive_ckd_mul_size(&bufsize, bufsize, 2))
break;
free(allocated);
allocated = malloc(bufsize);
if (allocated == NULL)
@@ -203,7 +205,8 @@ lookup_uid(void *private_data, const char *uname, int64_t uid)
break;
if (r != ERANGE)
break;
bufsize *= 2;
if (archive_ckd_mul_size(&bufsize, bufsize, 2))
break;
free(allocated);
allocated = malloc(bufsize);
if (allocated == NULL)
@@ -40,6 +40,7 @@
#include "archive.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
#include "archive_integer.h"
#include "archive_private.h"
#include "archive_write_private.h"
#include "archive_write_set_format_private.h"
@@ -307,10 +308,16 @@ synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
/* Ensure space for the new mapping. */
if (cpio->ino_list_size <= cpio->ino_list_next) {
size_t newsize = cpio->ino_list_size < 512
? 512 : cpio->ino_list_size * 2;
void *newlist = realloc(cpio->ino_list,
sizeof(cpio->ino_list[0]) * newsize);
size_t newsize, size;
if (cpio->ino_list_size < 512)
newsize = 512;
else if (archive_ckd_mul_size(&newsize,
cpio->ino_list_size, 2))
return (-1);
if (archive_ckd_mul_size(&size,
newsize, sizeof(cpio->ino_list[0])))
return (-1);
void *newlist = realloc(cpio->ino_list, size);
if (newlist == NULL)
return (-1);
+11 -4
View File
@@ -40,6 +40,7 @@
#include "archive.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
#include "archive_integer.h"
#include "archive_private.h"
#include "archive_write_private.h"
#include "archive_write_set_format_private.h"
@@ -204,10 +205,16 @@ synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
/* Ensure space for the new mapping. */
if (cpio->ino_list_size <= cpio->ino_list_next) {
size_t newsize = cpio->ino_list_size < 512
? 512 : cpio->ino_list_size * 2;
void *newlist = realloc(cpio->ino_list,
sizeof(cpio->ino_list[0]) * newsize);
size_t newsize, size;
if (cpio->ino_list_size < 512)
newsize = 512;
else if (archive_ckd_mul_size(&newsize,
cpio->ino_list_size, 2))
return (-1);
if (archive_ckd_mul_size(&size,
newsize, sizeof(cpio->ino_list[0])))
return (-1);
void *newlist = realloc(cpio->ino_list, size);
if (newlist == NULL)
return (-1);
+5 -2
View File
@@ -450,8 +450,11 @@ write_archive(struct archive *a, struct bsdtar *bsdtar)
/* Choose a suitable copy buffer size */
bsdtar->buff_size = 64 * 1024;
while (bsdtar->buff_size < (size_t)bsdtar->bytes_per_block)
bsdtar->buff_size *= 2;
while (bsdtar->buff_size < (size_t)bsdtar->bytes_per_block) {
bsdtar->buff_size *= 2;
if (bsdtar->buff_size < 64 * 1024)
lafe_errc(1, 0, "cannot allocate memory");
}
/* Try to compensate for space we'll lose to alignment. */
bsdtar->buff_size += 16 * 1024;