mirror of
https://github.com/systemd/systemd.git
synced 2026-08-04 15:10:33 +00:00
hwdb: reject out-of-bounds fnmatch prefixes
Ensure that fnmatch traversal doesn't go off the hwdb.bin in case of a corrupted file Originally reported on yeswehack.com as #YWH-PGM9780-70 For the unit test: Co-developed-by: GitHub Copilot <github-copilot[bot]@users.noreply.github.com>
This commit is contained in:
@@ -180,9 +180,18 @@ static int trie_fnmatch_f(sd_hwdb *hwdb, const struct trie_node_f *node, size_t
|
||||
const char *prefix;
|
||||
int err;
|
||||
|
||||
assert(hwdb);
|
||||
assert(node);
|
||||
|
||||
/* Ensure the prefix is within bounds */
|
||||
uint64_t file_size = hwdb->st.st_size, prefix_off = le64toh(node->prefix_off);
|
||||
if (prefix_off >= file_size || p >= file_size - prefix_off)
|
||||
return -EINVAL;
|
||||
|
||||
prefix = trie_string(hwdb, node->prefix_off);
|
||||
len = strlen(prefix + p);
|
||||
linebuf_add(buf, prefix + p, len);
|
||||
len = strnlen(prefix + p, file_size - prefix_off - p);
|
||||
if (!linebuf_add(buf, prefix + p, len))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < node->children_count; i++) {
|
||||
const struct trie_child_entry_f *child = trie_node_child(hwdb, node, i);
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-hwdb.h"
|
||||
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "hwdb-internal.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "path-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "tests.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
TEST(failed_enumerate) {
|
||||
_cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
|
||||
@@ -69,6 +76,65 @@ TEST(sd_hwdb_new_from_path) {
|
||||
assert_se(r >= 0);
|
||||
}
|
||||
|
||||
TEST(sd_hwdb_seek_rejects_invalid_fnmatch_prefix) {
|
||||
_cleanup_(rm_rf_physical_and_freep) char *tmp = NULL;
|
||||
_cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
|
||||
struct invalid_hwdb {
|
||||
struct trie_header_f header;
|
||||
struct trie_node_f root_node;
|
||||
struct trie_child_entry_f child1;
|
||||
struct trie_node_f mid_node;
|
||||
struct trie_child_entry_f child2;
|
||||
struct trie_node_f crash_node;
|
||||
char strings[STRLEN("usb:") + 1];
|
||||
} _packed_ data = {
|
||||
.header = {
|
||||
.signature = HWDB_SIG,
|
||||
.tool_version = htole64(PROJECT_VERSION),
|
||||
.file_size = htole64(sizeof(struct invalid_hwdb)),
|
||||
.header_size = htole64(sizeof(struct trie_header_f)),
|
||||
.node_size = htole64(sizeof(struct trie_node_f)),
|
||||
.child_entry_size = htole64(sizeof(struct trie_child_entry_f)),
|
||||
.value_entry_size = htole64(sizeof(struct trie_value_entry_f)),
|
||||
.nodes_root_off = htole64(offsetof(struct invalid_hwdb, root_node)),
|
||||
.nodes_len = htole64(offsetof(struct invalid_hwdb, strings) - offsetof(struct invalid_hwdb, root_node)),
|
||||
.strings_len = htole64(STRLEN("usb:") + 1),
|
||||
},
|
||||
.root_node = {
|
||||
.prefix_off = htole64(offsetof(struct invalid_hwdb, strings)),
|
||||
.children_count = 1,
|
||||
},
|
||||
.child1 = {
|
||||
.c = 'v',
|
||||
.child_off = htole64(offsetof(struct invalid_hwdb, mid_node)),
|
||||
},
|
||||
.mid_node = {
|
||||
.prefix_off = htole64(offsetof(struct invalid_hwdb, strings) + STRLEN("usb:")),
|
||||
.children_count = 1,
|
||||
},
|
||||
.child2 = {
|
||||
.c = '*',
|
||||
.child_off = htole64(offsetof(struct invalid_hwdb, crash_node)),
|
||||
},
|
||||
.crash_node = {
|
||||
.prefix_off = htole64(0xDEAD0000),
|
||||
},
|
||||
.strings = "usb:",
|
||||
};
|
||||
|
||||
ASSERT_OK(mkdtemp_malloc(NULL, &tmp));
|
||||
ASSERT_NOT_NULL(path = path_join(tmp, "hwdb.bin"));
|
||||
|
||||
_cleanup_close_ int fd = ASSERT_OK_ERRNO(open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC, 0644));
|
||||
assert_se(write(fd, &data, sizeof(data)) == (ssize_t) sizeof(data));
|
||||
fd = safe_close(fd);
|
||||
|
||||
ASSERT_OK(sd_hwdb_new_from_path(path, &hwdb));
|
||||
ASSERT_ERROR(sd_hwdb_seek(hwdb, "usb:v*"), EINVAL);
|
||||
}
|
||||
|
||||
static int intro(void) {
|
||||
_cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
|
||||
int r;
|
||||
|
||||
Reference in New Issue
Block a user