From 6c6938d1e23fd66ddba4484c7c2c6031acbd7f15 Mon Sep 17 00:00:00 2001 From: Alexander Egorenkov Date: Tue, 30 Jun 2026 13:30:41 +0200 Subject: [PATCH] zdump/ngdump: Use OpenSSL's SHA256 to compute digest of dump image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the popen() call to the external tool sha256sum with OpenSSL's SHA256 digest algorithm to compute the checksum of a dump image to improve security of NGDump. The call to popen() is inherently insecure because a malicious user controlling a dump device could manipulate the latter and let the user applying zgetdump to the dump device execute arbitrary shell code. Furthermore, getting rid of process and shell spawning performed by popen() shall improve performance of calculation of dump image checksums. Signed-off-by: Alexander Egorenkov Reviewed-by: Mikhail Zaslonko Signed-off-by: Jan Höppner --- zdump/ngdump.c | 97 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 23 deletions(-) diff --git a/zdump/ngdump.c b/zdump/ngdump.c index bd58348f..905dfb2c 100644 --- a/zdump/ngdump.c +++ b/zdump/ngdump.c @@ -18,6 +18,8 @@ #include #include +#include + #include "lib/dasd_base.h" #include "lib/util_libc.h" #include "lib/util_part.h" @@ -96,35 +98,84 @@ static int read_meta_from_file(const char *filename, struct ngdump_meta *meta) static int calc_sha256sum(const char *filename, char **cksum) { + const unsigned long buflen = PAGE_SIZE; + const EVP_MD *digtype = EVP_sha256(); + const size_t diglen = EVP_MD_size(digtype); + unsigned char *digest; + EVP_MD_CTX *ctx = NULL; + size_t i; FILE *fp = NULL; - char *cmd = NULL; - char *line = NULL; + int n, rc; + void *buf; - *cksum = NULL; + buf = util_malloc(buflen); + digest = util_malloc(diglen); - util_asprintf(&cmd, "sha256sum %s", filename); - - fp = popen(cmd, "r"); - free(cmd); - if (!fp) - return -1; - - while (fscanf(fp, "%m[^\n]\n", &line) == 1) { - int n = sscanf(line, "%m[^ ]", cksum); - - free(line); - line = NULL; - - if (n == 1) - break; - - free(*cksum); - *cksum = NULL; + fp = fopen(filename, "r"); + if (!fp) { + util_log_print(UTIL_LOG_ERROR, + "%s: Could not open \"%s\" (%s)\n", + __func__, filename, strerror(errno)); + rc = -1; + goto out; } - pclose(fp); + ctx = EVP_MD_CTX_new(); + if (!ctx) { + rc = -1; + goto out; + } - return 0; + rc = EVP_DigestInit_ex(ctx, digtype, NULL); + if (!rc) { + rc = -1; + goto out; + } + + while (!feof(fp)) { + n = fread(buf, 1, buflen, fp); + if (ferror(fp)) { + util_log_print(UTIL_LOG_ERROR, + "%s: Could not read file \"%s\" (%s)\n", + __func__, filename, strerror(errno)); + rc = -1; + goto out; + } + + rc = EVP_DigestUpdate(ctx, buf, n); + if (!rc) { + rc = -1; + goto out; + } + } + + rc = EVP_DigestFinal(ctx, digest, NULL); + if (!rc) { + rc = -1; + goto out; + } + + /* Two characters for each digest byte and + additional one for string terminator */ + *cksum = util_malloc(diglen * 2 + 1); + + for (i = 0; i < diglen; i++) + sprintf(*cksum + 2 * i, "%02x", digest[i]); + + util_log_print(UTIL_LOG_DEBUG, + "%s: Dump checksum %s\n", + __func__, *cksum); + + rc = 0; + +out: + free(digest); + free(buf); + if (fp) + fclose(fp); + if (ctx) + EVP_MD_CTX_free(ctx); + return rc; } static int check_sha256sum(const char *filename, const char *expected_cksum)