diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-11-25 13:13:05 +0100 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-11-25 13:20:08 +0100 |
commit | fc9a644002dc501a5c224e5cc1a7dfba3ca2d1d8 (patch) | |
tree | 6fb1acf211a1bf9005236d16d22f03f8fac746d4 | |
parent | 2d303a7f0a6076bbf5739bae4f0fa443d0da5203 (diff) |
Cleanup: move overflow safe alloc code into libsquashfs
There were only a hand full of instances outside libsquashfs that used
the alloc code. In most cases, the thing allocated hat its size derived
from something already in memory anyway, so it is safe to assume its
size fits into a size_t.
At the same time, the opencoded Windows path conversion functions are
all unified into a single helper function.
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
34 files changed, 138 insertions, 100 deletions
diff --git a/difftool/Makemodule.am b/difftool/Makemodule.am index 7eb6600..7488ff1 100644 --- a/difftool/Makemodule.am +++ b/difftool/Makemodule.am @@ -2,6 +2,6 @@ sqfsdiff_SOURCES = difftool/sqfsdiff.c difftool/sqfsdiff.h difftool/util.c sqfsdiff_SOURCES += difftool/compare_dir.c difftool/node_compare.c sqfsdiff_SOURCES += difftool/compare_files.c difftool/super.c sqfsdiff_SOURCES += difftool/extract.c difftool/options.c -sqfsdiff_LDADD = libcommon.a libsquashfs.la libutil.la $(LZO_LIBS) libfstree.a +sqfsdiff_LDADD = libcommon.a libsquashfs.la libcompat.a $(LZO_LIBS) libfstree.a bin_PROGRAMS += sqfsdiff diff --git a/include/compat.h b/include/compat.h index 26ad69b..82b1c7e 100644 --- a/include/compat.h +++ b/include/compat.h @@ -59,6 +59,9 @@ #define le16toh(x) (x) #define le32toh(x) (x) #define le64toh(x) (x) + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> #else #include <endian.h> #endif @@ -164,4 +167,8 @@ char *strndup(const char *str, size_t max_len); int getsubopt(char **opt, char *const *keys, char **val); #endif +#if defined(_WIN32) || defined(__WINDOWS__) +WCHAR *path_to_windows(const char *input); +#endif + #endif /* COMPAT_H */ diff --git a/include/util/util.h b/include/util/util.h index 7aa4f31..ed1102b 100644 --- a/include/util/util.h +++ b/include/util/util.h @@ -18,19 +18,4 @@ #define container_of(ptr, type, member) \ ((type *)((char *)ptr - offsetof(type, member))) -/* - Helper for allocating data structures with flexible array members. - - 'base_size' is the size of the struct itself, 'item_size' the size of a - single array element and 'nmemb' the number of elements. - - Iternally checks for arithmetic overflows when allocating the combined thing. - */ -SQFS_INTERNAL -void *alloc_flex(size_t base_size, size_t item_size, size_t nmemb); - -/* Basically the same as calloc, but *ALWAYS* does overflow checking */ -SQFS_INTERNAL -void *alloc_array(size_t item_size, size_t nmemb); - #endif /* UTIL_H */ diff --git a/lib/common/comp_lzo.c b/lib/common/comp_lzo.c index 473b76f..cf5a362 100644 --- a/lib/common/comp_lzo.c +++ b/lib/common/comp_lzo.c @@ -176,7 +176,7 @@ static sqfs_compressor_t *lzo_create_copy(sqfs_compressor_t *cmp) lzo_compressor_t *other = (lzo_compressor_t *)cmp; lzo_compressor_t *lzo; - lzo = alloc_flex(sizeof(*lzo), 1, lzo_algs[other->algorithm].bufsize); + lzo = calloc(1, sizeof(*lzo) + lzo_algs[other->algorithm].bufsize); if (lzo == NULL) return NULL; @@ -209,8 +209,8 @@ sqfs_compressor_t *lzo_compressor_create(const sqfs_compressor_config_t *cfg) return NULL; } - lzo = alloc_flex(sizeof(*lzo), 1, - lzo_algs[cfg->opt.lzo.algorithm].bufsize); + lzo = calloc(1, + sizeof(*lzo) + lzo_algs[cfg->opt.lzo.algorithm].bufsize); base = (sqfs_compressor_t *)lzo; if (lzo == NULL) diff --git a/lib/common/mkdir_p.c b/lib/common/mkdir_p.c index a568567..0413495 100644 --- a/lib/common/mkdir_p.c +++ b/lib/common/mkdir_p.c @@ -12,9 +12,6 @@ #include <errno.h> #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> - /* Supported paths: - <letter>:\ <absolute path> @@ -85,25 +82,13 @@ static WCHAR *skip_prefix(WCHAR *ptr) int mkdir_p(const char *path) { WCHAR *wpath, *ptr, *end; - DWORD length, error; + DWORD error; bool done; - length = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) + 1; - wpath = alloc_array(sizeof(wpath[0]), length); - if (wpath == NULL) { - fprintf(stderr, "Converting UTF-8 path to UTF-16: %ld\n", - GetLastError()); + wpath = path_to_windows(path); + if (wpath == NULL) return -1; - } - - MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, length); - wpath[length - 1] = '\0'; - - for (ptr = wpath; *ptr != '\0'; ++ptr) { - if (*ptr == '/') - *ptr = '\\'; - } ptr = skip_prefix(wpath); if (ptr == NULL) { diff --git a/lib/common/serialize_fstree.c b/lib/common/serialize_fstree.c index 14a5a4e..42843e2 100644 --- a/lib/common/serialize_fstree.c +++ b/lib/common/serialize_fstree.c @@ -19,7 +19,7 @@ static sqfs_inode_generic_t *tree_node_to_inode(tree_node_t *node) if (S_ISLNK(node->mode)) extra = strlen(node->data.slink_target); - inode = alloc_flex(sizeof(*inode), 1, extra); + inode = calloc(1, sizeof(*inode) + extra); if (inode == NULL) { perror("creating inode"); return NULL; diff --git a/lib/common/write_export_table.c b/lib/common/write_export_table.c index c797577..c0d4993 100644 --- a/lib/common/write_export_table.c +++ b/lib/common/write_export_table.c @@ -20,7 +20,7 @@ int write_export_table(const char *filename, sqfs_file_t *file, if (fs->inode_tbl_size < 1) return 0; - table = alloc_array(sizeof(sqfs_u64), fs->inode_tbl_size); + table = calloc(1, sizeof(sqfs_u64) * fs->inode_tbl_size); if (table == NULL) { perror("Allocating NFS export table"); diff --git a/lib/compat/Makemodule.am b/lib/compat/Makemodule.am index fb37b46..7137f2c 100644 --- a/lib/compat/Makemodule.am +++ b/lib/compat/Makemodule.am @@ -1,5 +1,6 @@ libcompat_a_SOURCES = lib/compat/getline.c lib/compat/getsubopt.c libcompat_a_SOURCES += lib/compat/strndup.c lib/compat/mockups.c libcompat_a_SOURCES += lib/compat/chdir.c include/compat.h +libcompat_a_SOURCES += lib/compat/path_to_windows.c noinst_LIBRARIES += libcompat.a diff --git a/lib/compat/chdir.c b/lib/compat/chdir.c index b1b2d0c..04dcf17 100644 --- a/lib/compat/chdir.c +++ b/lib/compat/chdir.c @@ -10,37 +10,16 @@ #include "util/util.h" #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> #include <stdlib.h> int chdir(const char *path) { - WCHAR *wpath, *ptr; - DWORD length; + WCHAR *wpath; int ret; - length = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); - if (length <= 0) { - fprintf(stderr, "Converting '%s' to UTF-16: %ld\n", - path, GetLastError()); - return -1; - } - - wpath = alloc_array(sizeof(wpath[0]), length + 1); - if (wpath == NULL) { - fprintf(stderr, "Converting '%s' to UTF-16: out of memory\n", - path); + wpath = path_to_windows(path); + if (wpath == NULL) return -1; - } - - MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, length + 1); - wpath[length] = '\0'; - - for (ptr = wpath; *ptr != '\0'; ++ptr) { - if (*ptr == '/') - *ptr = '\\'; - } if (!SetCurrentDirectoryW(wpath)) { fprintf(stderr, "Switching to directory '%s': %ld\n", diff --git a/lib/compat/path_to_windows.c b/lib/compat/path_to_windows.c new file mode 100644 index 0000000..ff3a5d2 --- /dev/null +++ b/lib/compat/path_to_windows.c @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * path_to_windows.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "config.h" +#include "compat.h" + +#include <stdlib.h> +#include <stdio.h> + +#if defined(_WIN32) || defined(__WINDOWS__) +WCHAR *path_to_windows(const char *input) +{ + WCHAR *wpath, *ptr; + DWORD length; + + length = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); + if (length <= 0) { + fprintf(stderr, "Converting UTF-8 path to UTF-16: %ld\n", + GetLastError()); + return NULL; + } + + wpath = calloc(sizeof(wpath[0]), length + 1); + if (wpath == NULL) { + fprintf(stderr, + "Converting UTF-8 path to UTF-16: out of memory\n"); + return NULL; + } + + MultiByteToWideChar(CP_UTF8, 0, input, -1, wpath, length + 1); + wpath[length] = '\0'; + + for (ptr = wpath; *ptr != '\0'; ++ptr) { + if (*ptr == '/') + *ptr = '\\'; + } + + return wpath; +} +#endif diff --git a/lib/fstree/gen_inode_table.c b/lib/fstree/gen_inode_table.c index d97c645..a5a28c9 100644 --- a/lib/fstree/gen_inode_table.c +++ b/lib/fstree/gen_inode_table.c @@ -61,8 +61,7 @@ int fstree_gen_inode_table(fstree_t *fs) size_t inum = 1; fs->inode_tbl_size = count_nodes(fs->root); - fs->inode_table = alloc_array(sizeof(tree_node_t *), - fs->inode_tbl_size); + fs->inode_table = calloc(1, sizeof(tree_node_t*) * fs->inode_tbl_size); if (fs->inode_table == NULL) { perror("allocating inode table"); diff --git a/lib/sqfs/Makemodule.am b/lib/sqfs/Makemodule.am index be405cf..59cdbcb 100644 --- a/lib/sqfs/Makemodule.am +++ b/lib/sqfs/Makemodule.am @@ -24,6 +24,7 @@ libsquashfs_la_SOURCES += lib/sqfs/data_writer/internal.h lib/sqfs/data_reader.c libsquashfs_la_SOURCES += lib/sqfs/data_writer/common.c libsquashfs_la_SOURCES += lib/sqfs/data_writer/fileapi.c libsquashfs_la_SOURCES += lib/sqfs/str_table.c lib/sqfs/str_table.h +libsquashfs_la_SOURCES += lib/sqfs/alloc.c lib/sqfs/util.h libsquashfs_la_CPPFLAGS = $(AM_CPPFLAGS) libsquashfs_la_LDFLAGS = $(AM_LDFLAGS) libsquashfs_la_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS) diff --git a/lib/util/alloc.c b/lib/sqfs/alloc.c index 526a4d5..e8305d8 100644 --- a/lib/util/alloc.c +++ b/lib/sqfs/alloc.c @@ -6,9 +6,8 @@ */ #include "config.h" -#include "util/util.h" +#include "util.h" -#include <stddef.h> #include <stdlib.h> #include <errno.h> diff --git a/lib/sqfs/comp/internal.h b/lib/sqfs/comp/internal.h index dabf1a6..c687d41 100644 --- a/lib/sqfs/comp/internal.h +++ b/lib/sqfs/comp/internal.h @@ -14,7 +14,7 @@ #include "sqfs/error.h" #include "sqfs/block.h" #include "sqfs/io.h" -#include "util/util.h" +#include "../util.h" SQFS_INTERNAL int sqfs_generic_write_options(sqfs_file_t *file, const void *data, diff --git a/lib/sqfs/data_reader.c b/lib/sqfs/data_reader.c index b105096..6a0db35 100644 --- a/lib/sqfs/data_reader.c +++ b/lib/sqfs/data_reader.c @@ -14,7 +14,7 @@ #include "sqfs/table.h" #include "sqfs/inode.h" #include "sqfs/io.h" -#include "util/util.h" +#include "util.h" #include <stdlib.h> #include <string.h> diff --git a/lib/sqfs/data_writer/internal.h b/lib/sqfs/data_writer/internal.h index 9c64b6c..d6e26cd 100644 --- a/lib/sqfs/data_writer/internal.h +++ b/lib/sqfs/data_writer/internal.h @@ -16,7 +16,7 @@ #include "sqfs/error.h" #include "sqfs/block.h" #include "sqfs/io.h" -#include "util/util.h" +#include "../util.h" #include <string.h> #include <stdlib.h> diff --git a/lib/sqfs/dir_reader.c b/lib/sqfs/dir_reader.c index bae24d5..bda7d7a 100644 --- a/lib/sqfs/dir_reader.c +++ b/lib/sqfs/dir_reader.c @@ -14,7 +14,7 @@ #include "sqfs/inode.h" #include "sqfs/error.h" #include "sqfs/dir.h" -#include "util/util.h" +#include "util.h" #include <string.h> #include <stdlib.h> diff --git a/lib/sqfs/dir_writer.c b/lib/sqfs/dir_writer.c index 673c103..bdd5dd1 100644 --- a/lib/sqfs/dir_writer.c +++ b/lib/sqfs/dir_writer.c @@ -13,7 +13,7 @@ #include "sqfs/error.h" #include "sqfs/block.h" #include "sqfs/dir.h" -#include "util/util.h" +#include "util.h" #include <stdlib.h> #include <string.h> diff --git a/lib/sqfs/meta_reader.c b/lib/sqfs/meta_reader.c index 0b8b33a..19e856a 100644 --- a/lib/sqfs/meta_reader.c +++ b/lib/sqfs/meta_reader.c @@ -12,7 +12,7 @@ #include "sqfs/error.h" #include "sqfs/block.h" #include "sqfs/io.h" -#include "util/util.h" +#include "util.h" #include <stdlib.h> #include <string.h> diff --git a/lib/sqfs/meta_writer.c b/lib/sqfs/meta_writer.c index cdd34e8..acb2235 100644 --- a/lib/sqfs/meta_writer.c +++ b/lib/sqfs/meta_writer.c @@ -12,7 +12,7 @@ #include "sqfs/error.h" #include "sqfs/block.h" #include "sqfs/io.h" -#include "util/util.h" +#include "util.h" #include <string.h> #include <stdlib.h> diff --git a/lib/sqfs/read_inode.c b/lib/sqfs/read_inode.c index fa3ec31..11d7a1c 100644 --- a/lib/sqfs/read_inode.c +++ b/lib/sqfs/read_inode.c @@ -12,7 +12,7 @@ #include "sqfs/super.h" #include "sqfs/inode.h" #include "sqfs/dir.h" -#include "util/util.h" +#include "util.h" #include <stdlib.h> #include <string.h> diff --git a/lib/sqfs/read_super.c b/lib/sqfs/read_super.c index f5cc988..8b3f019 100644 --- a/lib/sqfs/read_super.c +++ b/lib/sqfs/read_super.c @@ -10,7 +10,7 @@ #include "sqfs/super.h" #include "sqfs/error.h" #include "sqfs/io.h" -#include "util/util.h" +#include "util.h" #include <string.h> diff --git a/lib/sqfs/read_table.c b/lib/sqfs/read_table.c index 747c8bc..096ac1a 100644 --- a/lib/sqfs/read_table.c +++ b/lib/sqfs/read_table.c @@ -12,7 +12,7 @@ #include "sqfs/table.h" #include "sqfs/block.h" #include "sqfs/io.h" -#include "util/util.h" +#include "util.h" #include <stdlib.h> diff --git a/lib/sqfs/read_tree.c b/lib/sqfs/read_tree.c index eaf7c16..5464595 100644 --- a/lib/sqfs/read_tree.c +++ b/lib/sqfs/read_tree.c @@ -15,7 +15,7 @@ #include "sqfs/inode.h" #include "sqfs/error.h" #include "sqfs/dir.h" -#include "util/util.h" +#include "util.h" #include <string.h> #include <stdlib.h> diff --git a/lib/sqfs/str_table.c b/lib/sqfs/str_table.c index 1ec0ef7..c0a364f 100644 --- a/lib/sqfs/str_table.c +++ b/lib/sqfs/str_table.c @@ -11,8 +11,8 @@ #include <string.h> #include "sqfs/error.h" -#include "util/util.h" #include "str_table.h" +#include "util.h" /* R5 hash function (borrowed from reiserfs) */ static sqfs_u32 strhash(const char *s) diff --git a/lib/sqfs/util.h b/lib/sqfs/util.h new file mode 100644 index 0000000..a379c0d --- /dev/null +++ b/lib/sqfs/util.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * util.h + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#ifndef SQFS_UTIL_H +#define SQFS_UTIL_H + +#include "config.h" +#include "sqfs/predef.h" +#include "compat.h" + +#include <stddef.h> + +/* + Helper for allocating data structures with flexible array members. + + 'base_size' is the size of the struct itself, 'item_size' the size of a + single array element and 'nmemb' the number of elements. + + Iternally checks for arithmetic overflows when allocating the combined thing. + */ +SQFS_INTERNAL +void *alloc_flex(size_t base_size, size_t item_size, size_t nmemb); + +/* Basically the same as calloc, but *ALWAYS* does overflow checking */ +SQFS_INTERNAL +void *alloc_array(size_t item_size, size_t nmemb); + +#endif /* SQFS_UTIL_H */ diff --git a/lib/sqfs/write_table.c b/lib/sqfs/write_table.c index b8946a5..1931b83 100644 --- a/lib/sqfs/write_table.c +++ b/lib/sqfs/write_table.c @@ -13,7 +13,7 @@ #include "sqfs/table.h" #include "sqfs/block.h" #include "sqfs/io.h" -#include "util/util.h" +#include "util.h" #include <stdlib.h> diff --git a/lib/sqfs/xattr_reader.c b/lib/sqfs/xattr_reader.c index 250b4bd..d5b003b 100644 --- a/lib/sqfs/xattr_reader.c +++ b/lib/sqfs/xattr_reader.c @@ -14,7 +14,7 @@ #include "sqfs/error.h" #include "sqfs/block.h" #include "sqfs/io.h" -#include "util/util.h" +#include "util.h" #include <stdlib.h> #include <string.h> diff --git a/lib/sqfs/xattr_writer.c b/lib/sqfs/xattr_writer.c index 2e6a074..047e411 100644 --- a/lib/sqfs/xattr_writer.c +++ b/lib/sqfs/xattr_writer.c @@ -15,8 +15,8 @@ #include "sqfs/block.h" #include "sqfs/io.h" -#include "util/util.h" #include "str_table.h" +#include "util.h" #include <stdlib.h> #include <string.h> diff --git a/lib/util/Makemodule.am b/lib/util/Makemodule.am index 426e088..0ee762b 100644 --- a/lib/util/Makemodule.am +++ b/lib/util/Makemodule.am @@ -1,4 +1,4 @@ -libutil_la_SOURCES = include/util/util.h lib/util/alloc.c +libutil_la_SOURCES = include/util/util.h libutil_la_CFLAGS = $(AM_CFLAGS) libutil_la_CPPFLAGS = $(AM_CPPFLAGS) libutil_la_LDFLAGS = $(AM_LDFLAGS) diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index 7484618..6ddcdb0 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -50,6 +50,7 @@ static int pack_files(sqfs_data_writer_t *data, fstree_t *fs, const char *path; char *node_path; file_info_t *fi; + size_t size; int ret; if (set_working_dir(opt)) @@ -90,8 +91,16 @@ static int pack_files(sqfs_data_writer_t *data, fstree_t *fs, if (filesize % opt->cfg.block_size) ++max_blk_count; - inode = alloc_flex(sizeof(*inode), sizeof(sqfs_u32), - max_blk_count); + if (SZ_MUL_OV(sizeof(sqfs_u32), max_blk_count, &size) || + SZ_ADD_OV(sizeof(*inode), size, &size)) { + fputs("creating file inode: too many blocks\n", + stderr); + file->destroy(file); + free(node_path); + return -1; + } + + inode = calloc(1, size); if (inode == NULL) { perror("creating file inode"); file->destroy(file); diff --git a/tar/tar2sqfs.c b/tar/tar2sqfs.c index d0f2851..0076537 100644 --- a/tar/tar2sqfs.c +++ b/tar/tar2sqfs.c @@ -6,6 +6,7 @@ */ #include "config.h" #include "common.h" +#include "compat.h" #include "tar.h" #include <stdlib.h> @@ -213,7 +214,7 @@ static int write_file(tar_header_decoded_t *hdr, file_info_t *fi, { const sparse_map_t *it; sqfs_inode_generic_t *inode; - size_t max_blk_count; + size_t size, max_blk_count; sqfs_file_t *file; sqfs_u64 sum; int ret; @@ -222,7 +223,14 @@ static int write_file(tar_header_decoded_t *hdr, file_info_t *fi, if (filesize % cfg.block_size) ++max_blk_count; - inode = alloc_flex(sizeof(*inode), sizeof(sqfs_u32), max_blk_count); + if (SZ_MUL_OV(sizeof(sqfs_u32), max_blk_count, &size) || + SZ_ADD_OV(sizeof(*inode), size, &size)) { + fputs("creating file inode: too many blocks\n", + stderr); + return -1; + } + + inode = calloc(1, size); if (inode == NULL) { perror("creating file inode"); return -1; diff --git a/tests/Makemodule.am b/tests/Makemodule.am index 72d99ba..62cf813 100644 --- a/tests/Makemodule.am +++ b/tests/Makemodule.am @@ -2,6 +2,7 @@ test_canonicalize_name_SOURCES = tests/canonicalize_name.c test_canonicalize_name_LDADD = libfstree.a test_str_table_SOURCES = tests/str_table.c lib/sqfs/str_table.c +test_str_table_SOURCES += lib/sqfs/alloc.c lib/sqfs/util.h test_str_table_SOURCES += lib/sqfs/str_table.h test_str_table_LDADD = libutil.la libcompat.a test_str_table_CPPFLAGS = $(AM_CPPFLAGS) -DTESTPATH=$(top_srcdir)/tests diff --git a/unpack/restore_fstree.c b/unpack/restore_fstree.c index 7cecf16..1de9b05 100644 --- a/unpack/restore_fstree.c +++ b/unpack/restore_fstree.c @@ -9,22 +9,12 @@ #ifdef _WIN32 static int create_node(const sqfs_tree_node_t *n, const char *name) { - WCHAR *wpath = NULL; - DWORD length; + WCHAR *wpath; HANDLE fh; - length = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) + 1; - if (length <= 0) - goto fail; - - wpath = alloc_array(sizeof(wpath[0]), length); - if (wpath == NULL) { - perror(name); + wpath = path_to_windows(name); + if (wpath == NULL) return -1; - } - - MultiByteToWideChar(CP_UTF8, 0, name, -1, wpath, length); - wpath[length - 1] = '\0'; switch (n->inode->base.mode & S_IFMT) { case S_IFDIR: |