hwdb: strip the root from filenames when generating hwdb.bin

The modern hwdb.bin format contains the filenames of the input data that
makes up the database.  This is useful but in offline builds where
--root is used, the filenames are the full build paths including the
specified root.  This introduces build paths and thus information
leakage and non-reproducible data.

Solve this by stripping the root prefix off the original path when
passing to import_file.

Add TEST-17-UDEV.hwdb.sh to verify that hwdb.bin files contain the
path inside the root, but not the path of the root.
This commit is contained in:
Ross Burton
2026-07-20 14:31:15 +01:00
parent d024c58b8e
commit ab9be70e94
2 changed files with 56 additions and 4 deletions
+21 -4
View File
@@ -578,7 +578,7 @@ static int import_file(struct trie *trie, int fd, const char *filename, uint16_t
}
int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool compat) {
_cleanup_free_ char *hwdb_bin = NULL;
_cleanup_free_ char *hwdb_bin = NULL, *root_abs = NULL;
_cleanup_(trie_freep) struct trie *trie = NULL;
uint16_t file_priority = 1;
int r, ret = 0;
@@ -588,7 +588,18 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co
* source. If true, then hwdb.bin will be created without the information. systemd-hwdb command
* should set the argument false, and 'udevadm hwdb' command should set it true. */
hwdb_bin = path_join(root, hwdb_bin_dir ?: "/etc/udev", "hwdb.bin");
r = empty_or_root_harder_to_null(&root);
if (r < 0)
return log_error_errno(r, "Failed to determine if '%s' points to the root directory: %m", strempty(root));
if (root) {
r = path_make_absolute_cwd(root, &root_abs);
if (r < 0)
return log_error_errno(r, "Failed to make '%s' absolute: %m", root);
path_simplify(root_abs);
}
hwdb_bin = path_join(root_abs, hwdb_bin_dir ?: "/etc/udev", "hwdb.bin");
if (!hwdb_bin)
return -ENOMEM;
@@ -613,7 +624,7 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co
CLEANUP_ARRAY(files, n_files, conf_file_free_array);
r = conf_files_list_strv_full(".hwdb", root,
r = conf_files_list_strv_full(".hwdb", root_abs,
CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED | CONF_FILES_WARN,
conf_file_dirs, &files, &n_files);
if (r < 0)
@@ -635,7 +646,13 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co
ConfFile *c = *i;
log_debug("Reading file \"%s\" -> \"%s\"", c->original_path, c->resolved_path);
RET_GATHER(ret, import_file(trie, c->fd, c->original_path, file_priority++, compat));
const char *path_in_root = path_startswith_full(c->original_path,
empty_to_root(root_abs),
PATH_STARTSWITH_RETURN_LEADING_SLASH);
assert(path_in_root);
RET_GATHER(ret, import_file(trie, c->fd, path_in_root, file_priority++, compat));
}
strbuf_complete(trie->strings);
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
if ! command -v systemd-hwdb >/dev/null; then
echo "systemd-hwdb not found, skipping."
exit 0
fi
# shellcheck source=test/units/util.sh
. "$(dirname "$0")"/util.sh
at_exit() (
set +e
[[ -d "$ROOTFS" ]] && rm -rf "$ROOTFS"
)
trap at_exit EXIT
ROOTFS="$(mktemp -d -t test-17-udev-hwdb.XXXX)"
HWDB=$ROOTFS/usr/lib/udev/hwdb.d
mkdir -p "$HWDB"
cat >"$HWDB/99-test.hwdb" <<EOF
scsi:*
ID_TEST=test
EOF
systemd-hwdb update --root "$ROOTFS" --usr
# check the rootfs path does not appear in hwdb.bin
run_and_grep -n "$ROOTFS" strings "$ROOTFS/usr/lib/udev/hwdb.bin"
# check the path in the rootfs does appear in hwdb.bin
run_and_grep 99-test.hwdb strings "$ROOTFS/usr/lib/udev/hwdb.bin"