From b60f9276096879d2bba4cc702407855650cdf34b Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Thu, 1 Dec 2011 18:40:27 +0200 Subject: [PATCH] directory hash calculation Directory integrity verification requires directory hash value to be set to security.ima. This patch provides directory hash calculation. Signed-off-by: Dmitry Kasatkin --- src/evmctl.c | 94 ++++++++++++++++++++++++++++++++++++++++++- tests/evm_hmac_all.sh | 2 +- 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/src/evmctl.c b/src/evmctl.c index 32c0b71..751e48f 100644 --- a/src/evmctl.c +++ b/src/evmctl.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -543,15 +544,106 @@ static int calc_file_hash(const char *file, uint8_t *hash) return mdlen; } +struct dirent_list { + struct dirent_list *next; + struct dirent de; +}; + +static int calc_dir_hash(const char *file, uint8_t *hash) +{ + EVP_MD_CTX ctx; + const EVP_MD *md; + int err; + unsigned int mdlen; + struct dirent *de; + DIR *dir; + struct dirent_list *head = NULL, *pos, *prev, *cur; + uint64_t ino; + + dir = opendir(file); + if (!dir) { + log_errno("Unable to open %s", file); + return -1; + } + + OpenSSL_add_all_digests(); + + md = EVP_get_digestbyname(hash_algo); + if (!md) { + log_errno("EVP_get_digestbyname() failed"); + return -1; + } + + err = EVP_DigestInit(&ctx, md); + if (!err) { + log_errno("EVP_DigestInit() failed"); + return -1; + } + + while ((de = readdir(dir))) { + //printf("entry: ino: %lu, %s\n", de->d_ino, de->d_name); + for (prev = NULL, pos = head; pos; prev = pos, pos = pos->next) { + if (de->d_ino < pos->de.d_ino) + break; + } + cur = malloc(sizeof(*cur)); + cur->de = *de; + cur->next = pos; + if (!head || !prev) + head = cur; + else + prev->next = cur; + } + + for (cur = head; cur; cur = pos) { + pos = cur->next; + ino = cur->de.d_ino; + log_debug("entry: ino: %llu, %s\n", ino, cur->de.d_name); + err = EVP_DigestUpdate(&ctx, cur->de.d_name, strlen(cur->de.d_name)); + if (!err) { + log_errno("EVP_DigestUpdate() failed"); + return -1; + } + err = EVP_DigestUpdate(&ctx, &ino, sizeof(ino)); + if (!err) { + log_errno("EVP_DigestUpdate() failed"); + return -1; + } + free(cur); + } + + err = EVP_DigestFinal(&ctx, hash, &mdlen); + if (!err) { + log_errno("EVP_DigestFinal() failed"); + return -1; + } + + closedir(dir); + + return mdlen; +} + static int hash_ima(const char *file) { unsigned char hash[65] = "\x01";// MAX hash size + 1 int err; + struct stat st; - err = calc_file_hash(file, hash + 1); + /* Need to know the file length */ + err = stat(file, &st); + if (err < 0) + return err; + + if (S_ISDIR(st.st_mode)) + err = calc_dir_hash(file, hash + 1); + else + err = calc_file_hash(file, hash + 1); if (err < 0) return err; + if (verbose >= LOG_INFO) + log_info("hash: "); + if (!set_xattr || verbose >= LOG_INFO) dump(hash, err + 1); diff --git a/tests/evm_hmac_all.sh b/tests/evm_hmac_all.sh index 5b73764..de269f5 100755 --- a/tests/evm_hmac_all.sh +++ b/tests/evm_hmac_all.sh @@ -10,5 +10,5 @@ dir=${1:-/} echo "Label: $dir" -find $dir \( -fstype rootfs -o -fstype ext3 -o -fstype ext4 \) -type f -uid 0 -exec evmctl hmac --imahash $verbose '{}' \; +find $dir \( -fstype rootfs -o -fstype ext3 -o -fstype ext4 \) \( -type f -o -type d \) -uid 0 -exec evmctl hmac --imahash $verbose '{}' \;