From a048670becd7bf7a5354d9d156b511c104885d44 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 6 Jul 2026 14:21:26 +0200 Subject: [PATCH] zdev: Harden against invalid hypervisor data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduce chances of unintended side-effects when evaluating hypervisor data which might have been corrupted. Reviewed-by: Vineeth Vijayan Reviewed-by: Jan Höppner Signed-off-by: Peter Oberparleiter Signed-off-by: Jan Höppner --- zdev/dracut/95zdev/parse-zdev.sh | 16 +++++++++++++--- zdev/include/sanitize.h | 32 ++++++++++++++++++++++++++++++++ zdev/src/zdev_id.c | 2 ++ 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 zdev/include/sanitize.h diff --git a/zdev/dracut/95zdev/parse-zdev.sh b/zdev/dracut/95zdev/parse-zdev.sh index 31979f8b..a87e0bcb 100644 --- a/zdev/dracut/95zdev/parse-zdev.sh +++ b/zdev/dracut/95zdev/parse-zdev.sh @@ -41,9 +41,19 @@ if [ $zdev_auto -eq 1 ] ; then chzdev --import "$zdev_fw_file" $zdev_base_args # Get information about DPM environment - for line in $($zdev_id) ; do - eval "$line" - done + tmp="/tmp/zdev_id.env" + if "$zdev_id" >"$tmp"; then + while IFS='=' read -r key val; do + case "$key" in + ZDEV_*) + val=${val#\"} + val=${val%\"} + export "$key=$val" + ;; + esac + done <"$tmp" + fi + rm -f "$tmp" if [ "$ZDEV_IS_DPM,$ZDEV_NEST_LEVEL,$ZDEV_HYPERVISOR_0" = "1,1,LPAR" ] ; then # Manually iterate over existing PCI devices - there is a udev rule diff --git a/zdev/include/sanitize.h b/zdev/include/sanitize.h new file mode 100644 index 00000000..764a65f5 --- /dev/null +++ b/zdev/include/sanitize.h @@ -0,0 +1,32 @@ +/* + * zdev - Modify and display the persistent configuration of devices + * + * Copyright IBM Corp. 2026 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef SANITIZE_H +#define SANITIZE_H + +#include +#include + +/* Valid control-program identifier special characters */ +#define VALID_CPNAME "/" + +static inline int is_safe_char(unsigned char c, const char *set) +{ + return isalnum(c) || strchr(set, c); +} + +static inline void sanitize(char *s, const char *set) +{ + for (; *s; s++) { + if (!is_safe_char((unsigned char)*s, set)) + *s = '_'; + } +} + +#endif /* SANITIZE_H */ diff --git a/zdev/src/zdev_id.c b/zdev/src/zdev_id.c index a98acdd8..e64066ec 100644 --- a/zdev/src/zdev_id.c +++ b/zdev/src/zdev_id.c @@ -13,6 +13,7 @@ #include #include +#include "sanitize.h" #include "zdev.h" #include "zdev_id.h" @@ -69,6 +70,7 @@ static void process_sysinfo(const char *filename) free(substr); } else if (sscanf(line, "VM%*d Control Program: %ms ", &substr) == 1) { + sanitize(substr, VALID_CPNAME); array_add(&cps, &num_cps, substr); free(substr); }