提交 fa76af91 编写于 作者: R Roberto Sassu

digest-list-tools: tools

This patch adds the tools necessary to generate/verify digest lists and
metadata.
Signed-off-by: NRoberto Sassu <roberto.sassu@huawei.com>
上级 531f235d
#! /bin/bash
# Copyright (C) 2017 Huawei Technologies Duesseldorf GmbH
#
# Author: Roberto Sassu <roberto.sassu@huawei.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, version 2 of the
# License.
#
# File: setup_ima_digest_list
# Configure digest lists
set -f
function usage() {
echo "Usage: $0 initial|immutable|mutable [options]"
echo "Options:"
echo -e "\t-d <directory>: directory where digest lists and metadata are stored"
echo -e "\t-e <algorithm>: digest algorithm"
echo -e "\t-a: append metadata"
}
if [ "$1" != "initial" ] && [ "$1" != "immutable" ] && [ "$1" != "mutable" ]; then
usage
exit 1
fi
OPTIND=2
digest_lists_dir="/etc/ima/digest_lists"
algorithm="sha256"
gen_digest_lists_result=0
while getopts "h?d:e:a" opt; do
case "$opt" in
h|\?)
usage
exit 0
;;
d) digest_lists_dir=$OPTARG
;;
e) algorithm=$OPTARG
;;
a) gen_digest_lists_opt="-a"
;;
esac
done
if [ -z "$gen_digest_lists_opt" ] && [ -d "$digest_lists_dir" ]; then
ls_output=$(ls $digest_lists_dir)
if [ -n "$ls_output" ]; then
echo "$digest_lists_dir not empty, files will be overwritten. Do you want to continue? [y/N]"
read answer
if [ "$answer" != "y" ]; then
echo "Exiting."
exit 0
fi
fi
else
mkdir -p $digest_lists_dir
fi
if [ "$1" = "initial" ]; then
# generate digest lists from RPM database
echo "Generate initial digest list from RPM database"
gen_digest_lists $gen_digest_lists_opt -e $algorithm -d $digest_lists_dir -o rpm
gen_digest_lists_result=$?
elif [ "$1" = "immutable" ]; then
filename="$digest_lists_dir/unknown_digests_immutable"
find_opt="! -path /var/* ! -path /boot/*"
awk_opt='$5 !~ /^\/var/'
elif [ "$1" = "mutable" ]; then
# required if root filesystem is mounted as read-only
mount -t tmpfs none /var/tmp
cp -a /etc/ima/digest_lists /var/tmp
mount -t tmpfs none /etc/ima/digest_lists
cp -a /var/tmp/digest_lists /etc/ima
filename="/etc/ima/digest_lists/unknown_digests_mutable"
gen_digest_lists_opt="$gen_digest_lists_opt -w"
awk_opt='{print $0}'
fi
if [ -n "$filename" ]; then
# find unknown files in the root filesystem
echo "Read files from / and /boot"
find / /boot -xdev -type f -uid 0 $find_opt -exec head -c0 \{} \;
# create an ASCII file containing the digests of unknown measurements
echo "Create $filename with digests of unknown files"
cat /sys/kernel/security/ima/ascii_runtime_measurements | awk "$awk_opt" | \
awk '$4 != "sha1:0000000000000000000000000000000000000000" {print $4, $5}' > $filename
# edit the list of unknown digests
vi $filename
# create a digest list with the digest of immutable or mutable files
echo "Generate compact list from $filename"
gen_digest_lists -e $algorithm -d /etc/ima/digest_lists -f ascii -i $filename $gen_digest_lists_opt
gen_digest_lists_result=$?
fi
if [ $gen_digest_lists_result -eq 0 ]; then
# update initial ram disk
echo "Update initial ram disk"
dracut -f -i /etc/ima /etc/ima
fi
if [ "$1" = "mutable" ]; then
umount /var/tmp
umount /etc/ima/digest_lists
fi
set +f
/*
* Copyright (C) 2017 Huawei Technologies Duesseldorf GmbH
*
* Author: Roberto Sassu <roberto.sassu@huawei.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*
* File: gen_digest_lists.c
* Handles command line options and retrieve digests.
*/
#include <stdio.h>
#include <fcntl.h>
#include "metadata.h"
static int digest_list_from_rpmdb(char *outdir, char *metadata_filename,
enum digest_data_types output_fmt)
{
rpmts ts = NULL;
Header hdr;
rpmdbMatchIterator mi;
int ret;
ts = rpmtsCreate();
ret = rpmReadConfigFiles(NULL, NULL);
if (ret != RPMRC_OK) {
rpmlog(RPMLOG_NOTICE, "Unable to read RPM configuration.\n");
exit(1);
}
mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
while ((hdr = rpmdbNextIterator(mi)) != NULL) {
hdr = headerLink(hdr);
ret = write_digests_and_metadata(hdr, outdir, metadata_filename,
INPUT_FMT_RPMDB, NULL,
output_fmt, 0);
if (ret < 0)
break;
headerFree(hdr);
}
rpmdbFreeIterator(mi);
rpmtsFree(ts);
return ret;
}
int digest_lists_from_rpmpkg(char *outdir, char *metadata_filename,
char *package_path,
enum digest_data_types output_fmt)
{
Header hdr;
rpmts ts = NULL;
FD_t fd;
int ret;
fd = Fopen(package_path, "r.ufdio");
if ((!fd) || Ferror(fd)) {
rpmlog(RPMLOG_NOTICE, "Failed to open package file (%s)\n",
Fstrerror(fd));
if (fd)
Fclose(fd);
return -EINVAL;
}
ret = rpmReadPackageFile(ts, fd, package_path, &hdr);
if (ret != RPMRC_OK) {
rpmlog(RPMLOG_NOTICE, "Could not read package file\n");
Fclose(fd);
exit(1);
}
Fclose(fd);
ret = write_digests_and_metadata(hdr, outdir, metadata_filename,
INPUT_FMT_RPMPKG, NULL, output_fmt, 0);
rpmtsFree(ts);
return ret;
}
int write_digest_lists(char *outdir, char *metadata_filename,
int add_metadata, enum input_formats input_fmt,
char *input_filename, enum digest_data_types output_fmt,
int is_mutable)
{
char filename[MAX_FILENAME_LENGTH];
int ret = 0, fd;
snprintf(filename, sizeof(filename), "%s/%s", outdir,
metadata_filename);
fd = open(filename, O_WRONLY | O_CREAT, 0600);
if (fd < 0) {
printf("Unable to write metadata file %s\n", filename);
return -EACCES;
}
if (!add_metadata)
ftruncate(fd, 0);
switch (input_fmt) {
case INPUT_FMT_RPMDB:
ret = digest_list_from_rpmdb(outdir, filename, output_fmt);
break;
case INPUT_FMT_RPMPKG:
ret = digest_lists_from_rpmpkg(outdir, filename, input_filename,
output_fmt);
break;
case INPUT_FMT_DIGEST_LIST_ASCII:
ret = write_digests_and_metadata(NULL, outdir, filename,
INPUT_FMT_DIGEST_LIST_ASCII,
input_filename, output_fmt,
is_mutable);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
void usage(char *progname)
{
printf("Usage: %s <options>\n", progname);
printf("Options:\n");
printf("\t-a: append metadata to an existing file\n"
"\t-d <directory>: directory where digest lists and metadata "
"are stored\n"
"\t-f <input format>: format of the input where digests "
"are taken from\n"
"\t\trpmdb: RPM database\n"
"\t\trpmpkg: RPM package\n"
"\t\tascii: file containing ASCII digests for each line\n"
"\t-h: display help\n"
"\t-i <path>: path of the file where digests are taken from\n"
"\t-m <file name>: metadata file name\n"
"\t-o <output format>: output format of the digest list\n"
"\t\tcompact: compact digest list\n"
"\t\trpm: RPM package header\n"
"\t-w: files are mutable\n"
"\t-e <algorithm>: digest algorithm\n");
}
int main(int argc, char **argv)
{
int add_metadata = 0, is_mutable = 0;
char *input_filename = NULL, *metadata_filename = "metadata";
char *outdir = NULL;
enum input_formats input_fmt = INPUT_FMT_RPMDB;
enum digest_data_types output_fmt = DATA_TYPE_COMPACT_LIST;
int c, ret;
while ((c = getopt(argc, argv, "ad:f:i:m:o:hwe:")) != -1) {
switch (c) {
case 'a':
add_metadata = 1;
break;
case 'd':
outdir = optarg;
break;
case 'f':
if (strcmp(optarg, "rpmdb") == 0) {
input_fmt = INPUT_FMT_RPMDB;
} else if (strcmp(optarg, "rpmpkg") == 0) {
input_fmt = INPUT_FMT_RPMPKG;
} else if (strcmp(optarg, "ascii") == 0) {
input_fmt = INPUT_FMT_DIGEST_LIST_ASCII;
} else {
printf("Unknown input format %s\n", optarg);
return -EINVAL;
}
break;
case 'h':
usage(argv[0]);
return -EINVAL;
case 'i':
input_filename = optarg;
break;
case 'm':
metadata_filename = optarg;
break;
case 'o':
if (strcmp(optarg, "compact") == 0) {
output_fmt = DATA_TYPE_COMPACT_LIST;
} else if (strcmp(optarg, "rpm") == 0) {
output_fmt = DATA_TYPE_RPM;
} else {
printf("Unknown output format %s\n", optarg);
return -EINVAL;
}
break;
case 'w':
is_mutable = 1;
break;
case 'e':
if (ima_hash_setup(optarg)) {
printf("Unknown algorithm %s\n", optarg);
return -EINVAL;
}
break;
default:
printf("Unknown option %c\n", optopt);
return -EINVAL;
}
}
if (input_fmt != INPUT_FMT_RPMDB && input_filename == NULL) {
printf("Input file not specified\n");
return -EINVAL;
}
if (input_fmt == INPUT_FMT_RPMDB && input_filename != NULL) {
printf("Input file format not specified\n");
return -EINVAL;
}
if (outdir == NULL) {
printf("Output directory not specified\n");
return -EINVAL;
}
if (outdir[0] != '/') {
printf("Absolute path of output directory must be specified\n");
return -EINVAL;
}
OpenSSL_add_all_digests();
ret = write_digest_lists(outdir, metadata_filename, add_metadata,
input_fmt, input_filename, output_fmt,
is_mutable);
EVP_cleanup();
return ret;
}
/*
* Copyright (C) 2017 Huawei Technologies Duesseldorf GmbH
*
* Author: Roberto Sassu <roberto.sassu@huawei.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*
* File: verify_digest_lists.c
* Verify digest list metadata and digest lists
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include "kernel_ima.h"
#include "lib.h"
int verify_list_metadata(char *path, u8 *digest, int *num_digest_lists,
int *num_digests)
{
int digest_len = hash_digest_size[ima_hash_algo];
u8 metadata_digest[digest_len];
void *data, *datap;
loff_t size, mmap_size, cur_size = 0;
int digest_lists = 0;
int ret, fd;
fd = kernel_read_file_from_path(path, &data, &size, 0,
READING_DIGEST_LIST_METADATA);
if (fd < 0) {
pr_err("Unable to read: %s (%d)\n", path, fd);
return fd;
}
mmap_size = size;
ret = calc_digest(metadata_digest, data, size, ima_hash_algo);
if (ret < 0)
goto out;
if (memcmp(metadata_digest, digest, digest_len) != 0) {
pr_err("%s: integrity check failed\n", path);
ret = -EINVAL;
goto out;
}
datap = data;
while (size > 0) {
cur_size = ima_parse_digest_list_metadata(size, datap);
if (cur_size < 0) {
ret = -EINVAL;
goto out;
}
size -= cur_size;
datap += cur_size;
digest_lists++;
}
*num_digest_lists = digest_lists;
*num_digests = digests;
out:
munmap(data, mmap_size);
return ret;
}
void usage(char *progname)
{
printf("Usage: %s <options>\n", progname);
printf("Options:\n");
printf("\t-d: directory containing metadata and digest lists\n"
"\t-m <file name>: metadata file name\n"
"\t-i <digest>: expected digest of metadata\n"
"\t-h: display help\n"
"\t-e <algorithm>: digest algorithm\n");
}
int main(int argc, char *argv[])
{
int c, digest_len, num_digest_lists, num_digests, ret = -EINVAL;
u8 input_digest[SHA512_DIGEST_SIZE];
char *digest_ptr = NULL, *cur_dir = "./";
char *metadata_filename = "metadata";
while ((c = getopt(argc, argv, "d:m:i:he:")) != -1) {
switch (c) {
case 'd':
cur_dir = optarg;
break;
case 'm':
metadata_filename = optarg;
break;
case 'i':
digest_ptr = optarg;
break;
case 'h':
usage(argv[0]);
return -EINVAL;
case 'e':
if (ima_hash_setup(optarg)) {
printf("Unknown algorithm %s\n", optarg);
return -EINVAL;
}
break;
default:
printf("Unknown option %c\n", optopt);
return -EINVAL;
}
}
if (digest_ptr == NULL) {
printf("Expected metadata digest not specified\n");
return -EINVAL;
}
digest_list_path = cur_dir;
OpenSSL_add_all_digests();
digest_len = hash_digest_size[ima_hash_algo];
hex2bin(input_digest, digest_ptr, digest_len);
ret = verify_list_metadata(metadata_filename, input_digest,
&num_digest_lists, &num_digests);
if (ret == 0)
printf("num_digest_lists: %d, num_digests: %d\n",
num_digest_lists, num_digests);
EVP_cleanup();
return ret;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册