zdump/ngdump: Use OpenSSL's SHA256 to compute digest of dump image

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 <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Alexander Egorenkov
2026-06-30 13:30:41 +02:00
committed by Jan Höppner
parent 90ad42d814
commit 6c6938d1e2

View File

@@ -18,6 +18,8 @@
#include <unistd.h>
#include <sys/mount.h>
#include <openssl/evp.h>
#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)