From: Sascha Hauer Date: Mon, 1 Dec 2014 15:23:21 +0100 Subject: [PATCH] evmctl: add support for offline image preparation With this change it's possible to sign a directory hierarchy, so that a filesystem image (e.g. a 'ubifs') can be generated. Creating the ima and evm signatues for an image with 'evmctl' has two problems: 1) The inode-numbers of the files are different in the to be created image and in the current filesystem. 2) The inode generation can be different, too. These problems are solved in a 4-step process: 1) 'evmctl' generates signatures and writes them to the extended attribute (the usual process so far). 2) The image, for example a 'ubifs' image, is generated. 'mkfs.ubifs' generates the image (including extended attributes) and stores the used inode number into an extended attribute "user.image-inode-number". 3) 'evmct' is re-started to generate the signatures, this time with the additional paramter "--image". Instead of using an 'ioctl' to get the inode number and generation, the inode is read from the extended attribute "user.image-inode-number", the generation is set to "0". 4) The image (omitting the exteneded attribute "user.image-inode-number") is generated. This patch adds the command line parameter "--image" to read the inode number from the extended attribute "user.image-inode-number" instead of using an ioctl(). The inode generation is set to 0, too. Signed-off-by: Sascha Hauer Signed-off-by: Marc Kleine-Budde --- src/evmctl.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++-------- src/imaevm.h | 1 + src/libimaevm.c | 25 ++++++++++++++++++++++++- 3 files changed, 74 insertions(+), 9 deletions(-) diff --git a/src/evmctl.c b/src/evmctl.c index 5d664005e915..9003f7640c0f 100644 --- a/src/evmctl.c +++ b/src/evmctl.c @@ -337,6 +337,7 @@ static int calc_evm_hash(const char *file, unsigned char *hash) pctx = EVP_MD_CTX_new(); #endif const EVP_MD *md; + ino_t ino; if (lstat(file, &st)) { log_err("Failed to stat: %s\n", file); @@ -371,9 +372,25 @@ static int calc_evm_hash(const char *file, unsigned char *hash) } close(fd); } - log_info("generation: %u\n", generation); } + if (params.image_mode) { + char buf[128] = { }; + + err = lgetxattr(file, "user.image-inode-number", buf, sizeof(buf) - 1); + if (err < 0) { + log_err("image mode: xattr 'user.image-inode-number' not found.\n"); + return -1; + } + ino = strtoull(buf, NULL, 10); + generation = 0; + } else { + ino = st.st_ino; + } + + log_info("inode-number: %llu\n", (unsigned long long)ino); + log_info("generation: %u\n", generation); + list_size = llistxattr(file, list, sizeof(list)); if (list_size < 0) { log_err("llistxattr() failed\n"); @@ -439,7 +456,7 @@ static int calc_evm_hash(const char *file, unsigned char *hash) hmac_size = sizeof(*hmac); if (!evm_portable) { - hmac->ino = st.st_ino; + hmac->ino = ino; hmac->generation = generation; } hmac->uid = st.st_uid; @@ -450,7 +467,7 @@ static int calc_evm_hash(const char *file, unsigned char *hash) hmac_size = sizeof(*hmac); if (!evm_portable) { - hmac->ino = st.st_ino; + hmac->ino = ino; hmac->generation = generation; } hmac->uid = st.st_uid; @@ -461,7 +478,7 @@ static int calc_evm_hash(const char *file, unsigned char *hash) hmac_size = sizeof(*hmac); if (!evm_portable) { - hmac->ino = st.st_ino; + hmac->ino = ino; hmac->generation = generation; } hmac->uid = st.st_uid; @@ -1000,6 +1017,7 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h pctx = HMAC_CTX_new(); #endif const EVP_MD *md; + ino_t ino; key = file2bin(keyfile, NULL, &keylen); if (!key) { @@ -1038,10 +1056,26 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h close(fd); } + if (params.image_mode) { + char buf[128] = { }; + + err = lgetxattr(file, "user.image-inode-number", buf, sizeof(buf) - 1); + if (err < 0) { + log_err("image mode: xattr 'user.image-inode-number' not found.\n"); + goto out; + } + ino = strtoull(buf, NULL, 10); + generation = 0; + } else { + ino = st.st_ino; + } + + log_info("inode-number: %llu\n", (unsigned long long)ino); log_info("generation: %u\n", generation); list_size = llistxattr(file, list, sizeof(list)); if (list_size <= 0) { + err = -1; log_err("llistxattr() failed: %s\n", file); goto out; } @@ -1084,7 +1118,7 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h struct h_misc *hmac = (struct h_misc *)&hmac_misc; hmac_size = sizeof(*hmac); - hmac->ino = st.st_ino; + hmac->ino = ino; hmac->generation = generation; hmac->uid = st.st_uid; hmac->gid = st.st_gid; @@ -1093,7 +1127,7 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h struct h_misc_64 *hmac = (struct h_misc_64 *)&hmac_misc; hmac_size = sizeof(*hmac); - hmac->ino = st.st_ino; + hmac->ino = ino; hmac->generation = generation; hmac->uid = st.st_uid; hmac->gid = st.st_gid; @@ -1102,7 +1136,7 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h struct h_misc_32 *hmac = (struct h_misc_32 *)&hmac_misc; hmac_size = sizeof(*hmac); - hmac->ino = st.st_ino; + hmac->ino = ino; hmac->generation = generation; hmac->uid = st.st_uid; hmac->gid = st.st_gid; @@ -1666,6 +1700,9 @@ static void usage(void) " --smack use extra SMACK xattrs for EVM\n" " --m32 force EVM hmac/signature for 32 bit target system\n" " --m64 force EVM hmac/signature for 64 bit target system\n" + " -m, --image image generation mode:\n" + " Read inode number from xattr 'user.image-inode-number',\n" + " and force inode generation to 0.\n" " --ino use custom inode for EVM\n" " --uid use custom UID for EVM\n" " --gid use custom GID for EVM\n" @@ -1716,6 +1753,7 @@ static struct option opts[] = { {"recursive", 0, 0, 'r'}, {"m32", 0, 0, '3'}, {"m64", 0, 0, '6'}, + {"image", 0, 0, 'm'}, {"portable", 0, 0, 'o'}, {"smack", 0, 0, 128}, {"version", 0, 0, 129}, @@ -1774,7 +1812,7 @@ int main(int argc, char *argv[]) g_argc = argc; while (1) { - c = getopt_long(argc, argv, "hvnsda:e:op::fu::k:t:ri", opts, &lind); + c = getopt_long(argc, argv, "hvnsda:e:op::fu::k:t:rim", opts, &lind); if (c == -1) break; @@ -1847,6 +1885,9 @@ int main(int argc, char *argv[]) case '6': msize = 64; break; + case 'm': + params.image_mode = true; + break; case 128: evm_config_xattrnames = evm_extra_smack_xattrs; break; diff --git a/src/imaevm.h b/src/imaevm.h index ed92e4d8981d..7e32d09c6538 100644 --- a/src/imaevm.h +++ b/src/imaevm.h @@ -182,6 +182,7 @@ struct libevm_params { const char *evm_hash_algo; const char *keyfile; const char *keypass; + bool image_mode; }; struct RSA_ASN1_template { diff --git a/src/libimaevm.c b/src/libimaevm.c index 4c093a038b72..866f74b39b41 100644 --- a/src/libimaevm.c +++ b/src/libimaevm.c @@ -40,6 +40,7 @@ /* should we use logger instead for library? */ #define USE_FPRINTF +#define _GNU_SOURCE #include #include @@ -49,6 +50,7 @@ #include #include #include +#include #include #include @@ -224,7 +226,28 @@ static int add_dir_hash(const char *file, EVP_MD_CTX *ctx) } while ((de = readdir(dir))) { - ino = de->d_ino; + if (params.image_mode) { + char *name; + char buf[128] = { }; + + err = asprintf(&name, "%s/%s", file, de->d_name); + if (err == -1) { + log_err("failed to allocate mem\n"); + return err; + } + + err = lgetxattr(file, "user.image-inode-number", buf, sizeof(buf) - 1); + if (err < 0) { + log_err("image mode: xattr 'user.image-inode-number' not found.\n"); + return -1; + } + ino = strtoull(buf, NULL, 10); + + free(name); + } else { + ino = de->d_ino; + } + off = de->d_off; type = de->d_type; log_debug("entry: %s, ino: %llu, type: %u, off: %llu, reclen: %hu\n",