lkml.org 
[lkml]   [2008]   [Jul]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
SubjectLTP IMA path
From
Date
This LTP patch tests the LIM/IMA functionality.

Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
---
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/README
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/README
@@ -0,0 +1,50 @@
+These testcases test the Integrity Measurement Architecture(IMA).
+
+Requirements
+------------
+In order for all of the tests in the testsuite to complete successfully:
+ - A kernel with Linux Integrity Module(LIM), IMA, KALLSYMS,
+ TPM support and TPM driver builtin is required.
+ - The testsuite must be executed with root priveleges so that it
+ can access securityfs files, such as: security/ima/policy and
+ security/ima/ascii_runtime_measurement.
+ - securityfs must be mounted. The tests assume that it is mounted
+ as /sys/kernel/security.
+ - For the re-measurement test, the filesystem, from where these
+ testcases are run, must be mounted with i_version.
+
+Dependency
+----------
+The testsuite is dependent on the default policy being enabled, which
+measures all executables, all files mmapped for execute and all files
+open for read. Once the default policy has been replaced, the IMA
+measurement and re-measurement tests will fail, as well as the test to
+load a new policy. (A measurement policy may only be loaded once per
+boot.)
+
+Running the Testsuite
+---------------------
+From the ../ltp-base-<version>/testcases/kernel/security/integrity/ima
+directory, as root compile the IMA testsuite tools, by executing make. To
+run the testsuite, from the same directory, on the command line execute:
+ sh ./ima_test.sh.
+
+The testsuite results are sent to standard output for viewing.
+
+Running Individual Testcases
+----------------------------
+Individual testcases may be run by executing shell scripts found in
+the ../ltp-base-<version>/testcases/kernel/security/integrity/ima subdirecties.
+However, understanding the results of the individual testcases is
+dependent on the execution context. For example, executing
+load_policy.sh should return zero the first time it is executed, but
+subsequently, should return a non-zero value. Both are valid values,
+depending on the execution context. The same is true for measuring
+and re-measuring a file. Before the test measure policy is loaded,
+the measure and re-measure scripts should return zero.
+
+System State after running the Testsuite
+----------------------------------------
+After running the testsuite, the system is running with the test
+measurement policy. A reboot is required to install a different
+integrity measurement policy.
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/Makefile
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/Makefile
@@ -0,0 +1,13 @@
+SUBDIRS = tpm kmem tools
+
+all:
+ @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i ; done
+
+install:
+ @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i install ; done
+
+clean:
+ @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i clean ; done
+ rm -rf tmp
+ rm -rf measure/tmp
+
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/ima_test.sh
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/ima_test.sh
@@ -0,0 +1,175 @@
+#!/bin/bash
+# Copyright (C) 2008 IBM Corporation
+# Author: Mimi Zohar <zohar@us.ibm.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.
+
+# The default policy on boot measures all executables, all
+# mmapped executable files, and all files open for read.
+#
+# test 1: verify TPM is enabled.
+# test 2: verify creating and reading a new file causes a new
+# measurement to be added to the IMA measurement list.
+# test 3: verify modifying and reading the new file causes a new
+# measurement to be added to the IMA measurement list.
+# test 4: verify ability to load a new measurement policy
+# test 5: verify new policy does not add a measurement to the
+# IMA measurement list for files open for read.
+# test 6: verify inability to load subsequent measurement policy.
+# test 7: verify template hash value for ima entry is correct.
+# test 8: verify ima calculated aggregate pcr value or matches actual pcr value.
+# test 9: verify kmem-template hash
+
+# We have only one chance per boot for all of the tests in the testsuite
+# to succeed. So make sure we have everything we need, before starting
+# the tests.
+
+testid="IMA Test Conf:"
+# Must be root
+id=`id -u`
+if [ $id != 0 ]; then
+ echo "$testid Cannot execute test, must be running as root"
+ exit -1
+fi
+
+# securityfs must be enabled and mounted
+SECURITYFS=`mount | grep securityfs`
+if [ $? == 1 ]; then
+ SECURITYFS=/sys/kernel/security
+ `mount -t securityfs securityfs $SECURITYFS`
+ if [ $? == 1 ]; then
+ echo "$testid Cannot execute test as securityfs not" \
+ " enabled in kernel"
+ exit -1
+ fi
+fi
+SECURITYFS=`echo $SECURITYFS | sed 's/securityfs on //' | sed 's/ type .*//'`
+
+# IMA must be configured in the kernel
+IMA_DIR=$SECURITYFS/ima
+if [ ! -d $IMA_DIR ]; then
+ echo "$testid Cannot execute test as IMA not enabled in kernel"
+ exit -1
+fi
+
+# KALLSYMS must be configured in the kernel
+KALLSYMS=/proc/kallsyms
+if [ ! -f $KALLSYMS ]; then
+ echo "$testid Cannot execute kmem test as" \
+ "KALLSYMS not enabled in kernel"
+ exit -1
+fi
+
+
+# test 1:
+testid="IMA Test 1:"
+PCRS_PATH=`find /sys/devices/ | grep pcrs`
+if [ $? -eq 0 ]; then
+ if [ ! -f $PCRS_PATH ]; then
+ echo "$testid failed - TPM not enabled"
+ echo "(Assuming sysfs is mounted as /sys.)"
+ exit -1
+ else
+ echo "$testid succeeded - TPM enabled"
+ fi
+else
+ echo "$testid failed - TPM not enabled"
+ echo "(Assuming sysfs is mounted as /sys.)"
+fi
+
+# test 2:
+testid="IMA Test 2:"
+chmod a+x ./measure/read_measure.sh
+./measure/read_measure.sh "$testid"
+if [ $? -eq 0 ]; then
+ echo "$testid success - file measured"
+else
+ echo "$testid failed - file not measured"
+fi
+
+# test 3:
+testid="IMA Test 3:"
+chmod a+x ./measure/re-measure.sh
+./measure/re-measure.sh "$testid"
+if [ $? -eq 0 ]; then
+ echo "$testid success - modified file measured"
+else
+ echo "$testid failed - modified file not measured. "
+ echo "(Make sure filesystem is mounted with iversion.)"
+fi
+
+# test 4:
+testid="IMA Test 4:"
+cd loadpolicy
+chmod a+x ./load_policy.sh
+./load_policy.sh "$testid"
+if [ $? -eq 0 ]; then
+ echo "$testid success - loaded policy"
+else
+ echo "$testid failed - loading policy(permitted once per boot)"
+fi
+
+# test 5:
+testid="IMA Test 5:"
+cd ../measure
+# make sure that date has changed for measurement test
+sleep 1
+./read_measure.sh "$testid"
+if [ $? -eq 0 ]; then
+ echo "$testid failed - shouldn't have measured the file"
+ echo "(Verify loaded correct ima measurement policy.)"
+else
+ echo "$testid succeeded - didn't measure the file"
+fi
+
+# test 6:
+testid="IMA Test 6:"
+cd ../loadpolicy
+./load_policy.sh "$testid"
+if [ $? -eq 0 ]; then
+ echo "$testid failed - shouldn't have loaded a policy"
+else
+ echo "$testid succeeded - didn't load a policy"
+fi
+
+# test 7:
+testid="IMA Test 7:"
+cd ../tpm
+chmod a+x ./ima_measure
+./ima_measure --validate > /dev/null
+if [ $? -eq 0 ]; then
+ echo "$testid succeeded - verified ima template hash values."
+else
+ echo "$testid failed - errors in verifying ima template hash values."
+fi
+
+# test 8:
+testid="IMA Test 8:"
+aggregate_pcr=`./ima_measure --validate` > /dev/null
+cat $PCRS_PATH | while read line ; do
+ if [ "${line:0:6}" == "PCR-10" ] ; then
+ if [ "${line:8:67}" == "${aggregate_pcr:0:59}" ] ; then
+ echo "$testid succeeded - aggregate pcr value"\
+ "matches real pcr value."
+ else
+ echo "$testid failed - aggregate pcr value does"\
+ "not match real pcr value."
+ echo 'aggregate_pcr: ' $aggregate_pcr
+ echo 'real pcr: ' $line
+ fi
+ fi
+done
+
+# test 9:
+testid="IMA Test 9:"
+cd ../kmem
+chmod a+x ./kmem-test.sh
+./kmem-test.sh
+if [ $? -eq 0 ]; then
+ echo "$testid succeeded - verified kmem template measurement"
+else
+ echo "$testid: failed - kmem template measurement "
+fi
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/loadpolicy/load_policy.sh
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/loadpolicy/load_policy.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+# Copyright (C) 2008 IBM Corporation
+# Author: Mimi Zohar <zohar@us.ibm.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.
+
+# Load a policy into security/ima/policy by opening the file,
+# writing the rules one at a time and then closing the file.
+# The new policy takes effect after the security/ima/policy
+# is closed.
+
+verbose=0
+if [ $# == 1 ]; then
+ msg_prefix=" $1"
+elif [ $# == 0 ]; then
+ verbose=1
+fi
+
+SECURITYFS=`mount | grep securityfs`
+SECURITYFS=`echo $SECURITYFS | sed 's/securityfs on //' | sed 's/ type .*//'`
+IMA_POLICY=$SECURITYFS/ima/policy
+
+# LSM specific policy
+LSM_POLICY=./measure.selinux
+#LSM_POLICY=./measure.smack
+
+if [ ! -f $LSM_POLICY ]; then
+ if [ $verbose == 1 ] ; then
+ echo "$msg_prefix LSM specific policy does not exist"
+ fi
+ exit -1
+fi
+
+if [ ! -f $IMA_POLICY ]; then
+ if [ $verbose == 1 ] ; then
+ echo "$msg_prefix security/ima/policy does not exist"
+ fi
+ exit -1
+fi
+
+exec 4>$IMA_POLICY
+if [ $? != 0 ]; then
+ if [ $verbose == 1 ] ; then
+ echo "$msg_prefix open failed: security/ima/policy"
+ fi
+ exit -1
+else
+ cat $LSM_POLICY | while read line ; do
+ if [ "${line:0:1}" != "#" ] ; then
+ echo $line >&4
+ fi
+ done
+ if [ $verbose == 1 ] ; then
+ echo "$msg_prefix security/ima/policy updated"
+ fi
+fi
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/loadpolicy/measure.selinux
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/loadpolicy/measure.selinux
@@ -0,0 +1,18 @@
+#
+# Integrity measure policy
+#
+# PROC_SUPER_MAGIC
+dont_measure fsmagic=0x9fa0
+# SYSFS_MAGIC
+dont_measure fsmagic=0x62656572
+# DEBUGFS_MAGIC
+dont_measure fsmagic=0x64626720
+# TMPFS_MAGIC
+dont_measure fsmagic=0x01021994
+# SECURITYFS_MAGIC
+dont_measure fsmagic=0x73636673
+measure func=BPRM_CHECK
+measure func=FILE_MMAP mask=MAY_EXEC
+measure obj=user_u func=INODE_PERMISSION mask=MAY_READ
+#measure subj=system_u func=INODE_PERMISSION mask=MAY_READ
+#measure func=INODE_PERMISSION mask=MAY_READ
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/measure/re-measure.sh
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/measure/re-measure.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# Copyright (C) 2008 IBM Corporation
+# Author: Mimi Zohar <zohar@us.ibm.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.
+
+verbose=0
+if [ $# == 1 ]; then
+ msg_prefix=" $1"
+elif [ $# == 0 ]; then
+ verbose=1
+fi
+
+# Create and read a file
+# Check if the file was measured (i.e. contained in the ascii measurement list.)
+
+mkdir -p tmp
+echo `date` '- modifying file causes hash to change' >> tmp/test.txt
+cat tmp/test.txt > /dev/null
+cat /sys/kernel/security/ima/ascii_runtime_measurements > tmp/imalog
+
+# calculate and search for sha1sum of tmp/test.txt in tmp/imalog
+hash=`cat tmp/test.txt | sha1sum | sed 's/ -//'`
+if [ $verbose == 1 ] ; then
+ echo "$msg_prefix hash: $hash"
+fi
+`grep $hash tmp/imalog > /dev/null`
+if [ $? == 0 ]; then
+ if [ $verbose == 1 ] ; then
+ echo " TPM ascii measurement list contains sha1sum"
+ fi
+ exit 0
+else
+ if [ $verbose == 1 ] ; then
+ echo " TPM ascii measurement list does not contain"\
+ "sha1sum"
+ fi
+ exit -1
+fi
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/measure/read_measure.sh
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/measure/read_measure.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# Copyright (C) 2008 IBM Corporation
+# Author: Mimi Zohar <zohar@us.ibm.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.
+
+verbose=0
+if [ $# == 1 ]; then
+ msg_prefix=" $1"
+elif [ $# == 0 ]; then
+ verbose=1
+fi
+
+# Create and read a file
+# Check if the file was measured (i.e. contained in the ascii measurement list.)
+
+mkdir -p tmp
+echo `date` '- changing date causes changing hash value' > tmp/test.txt
+cat tmp/test.txt > /dev/null
+cat /sys/kernel/security/ima/ascii_runtime_measurements > tmp/imalog
+
+# calculate and search for sha1sum of tmp/test.txt in tmp/imalog
+hash=`cat tmp/test.txt | sha1sum | sed 's/ -//'`
+if [ $verbose == 1 ] ; then
+ echo "$msg_prefix hash: " $hash
+fi
+`grep $hash tmp/imalog > /dev/null`
+if [ $? == 0 ]; then
+ if [ $verbose == 1 ] ; then
+ echo "$msg_prefix TPM ascii measurement list contains sha1sum"
+ fi
+ exit 0
+else
+ if [ $verbose == 1 ] ; then
+ echo "$msg_prefix TPM ascii measurement list does not"\
+ "contain sha1sum"
+ fi
+ exit -1
+fi
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/tools/Makefile
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/tools/Makefile
@@ -0,0 +1,9 @@
+TARGETS := hex2bin
+
+all: $(TARGETS)
+
+hex2bin: hex2bin.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o hex2bin hex2bin.c
+
+clean:
+ rm -f hex2bin hex2bin.o
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/tools/hex2bin.c
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/tools/hex2bin.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.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.
+ *
+ * hex2bin.c
+ * - convert a hex string to binary
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+main()
+{
+ char *line = NULL;
+ ssize_t len, line_len = 0;
+ int h, i = 0;
+
+ len = getline(&line, &line_len, stdin);
+ for (i = 0; i < len; i += 2) {
+ sscanf(line + i, "%2x", &h);
+ putchar(h);
+ }
+ free(line);
+}
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/tpm/Makefile
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/tpm/Makefile
@@ -0,0 +1,9 @@
+TARGETS := ima_measure
+
+all: $(TARGETS)
+
+ima_measure: ima_measure.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o ima_measure ima_measure.c -lcrypto
+
+clean:
+ rm -f ima_measure ima_measure.o
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/tpm/ima_measure.c
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/tpm/ima_measure.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2008
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Mimi Zohar <zohar@us.ibm.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: ima_measure.c
+ *
+ * Calculate the aggregate-pcr value based on the IMA runtime binary
+ * measurements.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <openssl/sha.h>
+
+#define TCG_EVENT_NAME_LEN_MAX 255
+#define MAX_EVENT_SIZE 500
+
+static int failed_count = 0; /* number of template verifications failed */
+static int verify_template_hash = 1;
+static int verbose = 0;
+static int validate = 0;
+
+#define print_info(format, arg...) \
+ if (verbose) \
+ printf(format, ##arg)
+
+static u_int8_t pcr[SHA_DIGEST_LENGTH]; /* simulates the PCR aggregate */
+static u_int8_t zero[SHA_DIGEST_LENGTH];
+static u_int8_t fox[SHA_DIGEST_LENGTH];
+struct template {
+ u_int32_t pcr;
+ u_int8_t tdigest[SHA_DIGEST_LENGTH]; /* template digest */
+ u_int32_t tlen; /* template name size */
+};
+
+struct ima_inode_measure_entry {
+ u_int8_t digest[SHA_DIGEST_LENGTH]; /* sha1 measurement hash */
+ char file_name[TCG_EVENT_NAME_LEN_MAX + 1]; /*name + \0*/
+};
+
+/* print sha1 aggregate over the template measurements */
+static int display_pcr()
+{
+ int i;
+
+ print_info("PCRAggr (re-calculated):");
+ for (i = 0; i < 20; i++)
+ printf("%02X ", pcr[i] & 0xff);
+ print_info(".\n");
+}
+
+static void print_digest(u_int8_t *digest)
+{
+ int i;
+
+ for (i = 0; i < 20; i++)
+ print_info("%02X", (*(digest + i) & 0xff));
+}
+
+/*
+ * Calculate the template hash of an ima entry
+ * and compare it with the actual template hash value.
+ */
+static int verify_ima_tdigest(struct template *tdata,
+ struct ima_inode_measure_entry *ima)
+{
+ int rc;
+ SHA_CTX tmp;
+ u_int8_t digest[SHA_DIGEST_LENGTH];
+
+ /* Calc template hash for an ima entry */
+ SHA1_Init(&tmp);
+ SHA1_Update(&tmp, ima, sizeof *ima);
+ SHA1_Final(digest, &tmp);
+
+ rc = memcmp(digest, tdata->tdigest, sizeof digest);
+ if (rc) {
+ int i;
+
+ print_info("%s: template hash not valid\n", ima->file_name);
+ print_info("\t should be:");
+ print_digest(digest);
+ print_info("\n\t is:");
+ print_digest(tdata->tdigest);
+ print_info("\n");
+ }
+ return rc;
+}
+
+int process_event(int num, unsigned char *event, int len)
+{
+ int i;
+ char tname[TCG_EVENT_NAME_LEN_MAX + 1]; /* template_name */
+ u_int32_t tname_len; /* template name length */
+ struct template *tdata;
+
+ tdata = (struct template *)event;
+
+ print_info("%3d %03u %d", num, tdata->pcr, tdata->tlen);
+ if (tdata->tlen > TCG_EVENT_NAME_LEN_MAX) {
+ printf("ERROR: event name too long!\n");
+ exit(1);
+ }
+ memset(tname, 0, TCG_EVENT_NAME_LEN_MAX);
+ memcpy(&tname, &tdata->tlen +1, tdata->tlen);
+ print_digest(tdata->tdigest);
+ print_info(" %s ", (char *)(tname));
+
+ if (strcmp(tname, "boot_aggregate") == 0) {
+ print_info("\n");
+ return (sizeof *tdata + tdata->tlen + 2) /* separator */ ;
+ } else if (strcmp(tname, "ima") == 0) {
+ struct event_data {
+ u_int8_t digest[SHA_DIGEST_LENGTH];
+ int len; /* file_name length */
+ char file_name[TCG_EVENT_NAME_LEN_MAX + 1];/*name + \0*/
+ } *data;
+
+ data = (struct event_data *)((void *)tdata
+ + sizeof *tdata + tdata->tlen);
+ print_digest(data->digest);
+ data->file_name[data->len] = 0x00;
+ print_info(" %s\n", data->file_name);
+
+ if (validate && (memcmp(fox, tdata->tdigest, sizeof fox) != 0)){
+ struct ima_inode_measure_entry entry;
+
+ memset(&entry, 0, sizeof entry);
+ memcpy(&entry.digest, data->digest, 20);
+ strncpy(entry.file_name, data->file_name, data->len);
+ failed_count += verify_ima_tdigest(tdata, &entry);
+ }
+ return (sizeof *tdata + tdata->tlen + sizeof data->digest
+ + data->len + 4); /* null separator */
+ } else if (strcmp(tname, "kmem") == 0) {
+ struct event_data {
+ u_int8_t digest[SHA_DIGEST_LENGTH];
+ int len; /* file_name length */
+ char file_name[TCG_EVENT_NAME_LEN_MAX + 1];/*name + \0*/
+ } *data;
+
+ data = (struct event_data *)((void *)tdata
+ + sizeof *tdata + tdata->tlen);
+ print_digest(data->digest);
+ return (sizeof *tdata + tdata->tlen + sizeof data->digest
+ + data->len + 4); /* null separator */
+ }
+}
+
+int simulate_extend_pcr(u_int8_t digest[SHA_DIGEST_LENGTH])
+{
+ SHA_CTX c;
+
+ /* Extend simulated PCR with new template digest */
+ SHA1_Init(&c);
+ SHA1_Update(&c, pcr, SHA_DIGEST_LENGTH);
+ if (validate) {
+ if (memcmp(digest, zero, 20) == 0)
+ memset(digest, 0xFF, 20);
+ }
+ SHA1_Update(&c, digest, 20);
+ SHA1_Final(pcr, &c);
+}
+
+/*
+ * ima_measurements.c - calculate the aggregate-pcr value based on
+ * the IMA runtime binary measurements.
+ *
+ * format: ima_measurement [--validate] [--verify] [--verbose]
+ *
+ * --validate: forces validation of the aggregrate pcr value
+ * for an invalidated PCR. Replace all entries in the
+ * runtime binary measurement list with 0x00 hash values,
+ * which indicate the PCR was invalidated, either for
+ * "a time of measure, time of use"(ToMToU) error, or a
+ * file open for read was already open for write, with
+ * 0xFF's hash value, when calculating the aggregate
+ * pcr value.
+ *
+ * --verify: for all IMA template entries in the runtime binary
+ * measurement list, calculate the template hash value
+ * and compare it with the actual template hash value.
+ * Return the number of incorrect hash measurements.
+ *
+ * --verbose: For all entries in the runtime binary measurement
+ * list, display the generic template information. In
+ * addition, for IMA and KMEM templates, display template
+ * specific information.
+ *
+ * template info: list #, PCR-register #, template hash, template name
+ * IMA info: IMA hash, filename hint
+ * KMEM info: memory hash, reference name
+ *
+ * Ouput: displays the aggregate-pcr value
+ * Return code: if verification enabled, returns number of verification
+ * errors.
+ */
+int main(int argc, char *argv[])
+{
+ int i, fd, count = 0, len;
+ unsigned char event[MAX_EVENT_SIZE];
+ SHA_CTX c;
+ int remaining = 0;
+ struct template *tdata;
+
+ memset(pcr, 0, SHA_DIGEST_LENGTH); /* initial PCR content 0..0 */
+ memset(zero, 0, SHA_DIGEST_LENGTH);
+ memset(fox, 0xff, SHA_DIGEST_LENGTH);
+
+ for (i = 1; i < argc; i++) {
+ if (strncmp(argv[i], "--validate", 5) == 0)
+ validate = 1;
+ if (strncmp(argv[i], "--verbose", 6) == 0)
+ verbose = 1;
+ if (strncmp(argv[i], "--verify", 6) == 0)
+ verify_template_hash = 1;
+ }
+
+
+ fd = open("/sys/kernel/security/ima/binary_runtime_measurements",
+ O_RDONLY);
+ if (fd < 0) {
+ perror("Unable to open file\n");
+ return 1;
+ }
+ print_info( "### PCR HASH " \
+ "TEMPLATE-NAME\n");
+
+ while ((len = read(fd, event + remaining, MAX_EVENT_SIZE - remaining))
+ || remaining) {
+ if (len < 0) {
+ perror("Error reading from file.\n");
+ break;
+ }
+ len += remaining;
+ tdata = (struct template *)event;
+
+ simulate_extend_pcr(tdata->tdigest);
+ remaining = len - process_event(count++, event, len);
+
+ /* copy rest to buffer start */
+ memcpy(event, event + len - remaining, remaining);
+
+ }
+ close(fd);
+
+ display_pcr();
+ return failed_count;
+}
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/kmem/Makefile
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/kmem/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for kernel module
+#
+ifneq ($(KERNELRELEASE),)
+obj-m += kmem-template.o
+EXTRA_CFLAGS += -I$(PWD) -O
+
+else
+KDIR := /lib/modules/$(shell uname -r)/build
+#KDIR := /lib/modules/2.6.26-rc8-git3/build
+PWD := $(shell pwd)
+
+default:
+ $(MAKE) -C $(KDIR) M=$(PWD) modules
+endif
+
+
+clean :
+ rm -rf .tmp_versions
+ @find $(KBUILD_EXTMOD) $(RCS_FIND_IGNORE) \
+ \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
+ -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
+ -o -name '*.symvers' -o -name '*.markers' \
+ -o -name '*.order' \) \
+ -type f -print | xargs rm -f
+
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/kmem/kmem-template.c
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/kmem/kmem-template.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.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.
+ *
+ * kmem-template.c
+ * - defines a kernel memory template
+ * - reads from security/kmem-template "name length address"
+ * - collects and stores measurement from address for length bytes
+ * - security/kmem-template returns last memory read
+ */
+
+#include <asm/uaccess.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/notifier.h>
+#include <linux/security.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/security.h>
+#include <linux/integrity.h>
+#include <linux/ima.h>
+
+#define MY_NAME THIS_MODULE->name
+#define IMA_DIGEST_SIZE 20
+
+static int __init init_kmem_template(void);
+static void __exit cleanup_kmem_template(void);
+
+static unsigned char *lastbuf;
+static int lastbuf_len;
+
+struct kmem_data {
+ char name[25];
+ char *buf;
+ int buflen;
+ u8 digest[IMA_DIGEST_SIZE];
+};
+
+int calc_hash(int buflen, char *buf, char *digest)
+{
+ struct crypto_hash *tfm;
+ struct hash_desc desc;
+ struct scatterlist sg[1];
+ int error, result = 0;
+
+ tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm)) {
+ printk(KERN_INFO "%s: failed to load %s transform: %ld\n",
+ __func__, "sha1", PTR_ERR(tfm));
+ return -ENOSYS;
+ }
+ desc.tfm = tfm;
+ desc.flags = 0;
+ error = crypto_hash_init(&desc);
+ if (error) {
+ result = -EINVAL;
+ goto out;
+ }
+
+ sg_set_buf(sg, buf, buflen);
+ result = crypto_hash_update(&desc, sg, buflen);
+ if (!result) {
+ error = crypto_hash_final(&desc, digest);
+ if (error)
+ result = -EINVAL;
+ }
+
+out:
+ crypto_free_hash(tfm);
+ return result;
+}
+
+static int kmem_collect_measurement(void *d)
+{
+ struct kmem_data *data = (struct kmem_data *)d;
+
+ memset(data->digest, 0, sizeof data->digest);
+ calc_hash(data->buflen, data->buf, data->digest);
+ return 0;
+}
+
+/* Transform local kmem data to store data */
+void kmem_store_measurement(void *d)
+{
+ struct kmem_data *data = (struct kmem_data *)d;
+ struct ima_data idata;
+ struct ima_store_data *template = &idata.data.template;
+
+ idata.type = IMA_TEMPLATE;
+ template->name = "kmem";
+ template->len = sizeof *data;
+ template->data = (char *)data;
+ template->violation = 0;
+ integrity_store_measurement("ima", (void *)&idata);
+ return;
+}
+
+static void kmem_template_show(struct seq_file *m, void *e,
+ enum integrity_show_type show)
+{
+ struct kmem_data *data = (struct kmem_data *)e;
+ int filename_len;
+ char len[4];
+ int i;
+
+ for (i = 0; i < 20; i++) {
+ switch (show) {
+ case INTEGRITY_SHOW_ASCII:
+ seq_printf(m, "%02x", data->digest[i]);
+ break;
+ case INTEGRITY_SHOW_BINARY:
+ seq_putc(m, data->digest[i]);
+ default:
+ break;
+ }
+ }
+
+ switch (show) {
+ case INTEGRITY_SHOW_ASCII:
+ seq_printf(m, " %s %d \n", data->name, data->buflen);
+ break;
+ case INTEGRITY_SHOW_BINARY:
+ filename_len = strlen(data->name);
+ memcpy(len, &filename_len, 4);
+ for (i = 0; i < 4; i++)
+ seq_putc(m, len[i]);
+ for (i = 0; i < strlen(data->name); i++)
+ seq_putc(m, data->name[i]);
+ default:
+ break;
+ }
+}
+
+static struct template_operations kmem_ops = {
+ .collect_measurement = kmem_collect_measurement,
+ .store_measurement = kmem_store_measurement,
+ .display_template = kmem_template_show
+};
+
+static int kmem_add_measure(char *name, unsigned int buflen, unsigned int addr)
+{
+ struct kmem_data data;
+ int rc;
+
+ strncpy(data.name, name, sizeof data.name);
+ data.buflen = buflen;
+ data.buf = (char *)addr;
+ rc = integrity_collect_measurement("kmem", &data);
+ if (!rc) {
+ integrity_store_measurement("kmem", &data);
+ if (data.buflen > lastbuf_len)
+ kfree(lastbuf);
+ lastbuf = kzalloc(data.buflen, GFP_KERNEL);
+ if (lastbuf) {
+ lastbuf_len = data.buflen;
+ memcpy(lastbuf, data.buf, lastbuf_len);
+ }
+ }
+ return rc;
+}
+
+static ssize_t kmem_write_template(struct file *file, const char __user *buf,
+ size_t buflen, loff_t *ppos)
+{
+ char *data;
+ char name[26];
+ size_t result = 0, datalen;
+ int rc;
+ unsigned int addr, len;
+
+ datalen = buflen > 256 ? 256 : buflen;
+ data = kzalloc(datalen + 1, GFP_KERNEL);
+ if (!data)
+ result = -ENOMEM;
+
+ if (copy_from_user(data, buf, datalen)) {
+ result = -EFAULT;
+ goto out;
+ }
+ result = datalen;
+
+ rc = sscanf(data, "%25s %d %x ", name, &len, &addr);
+ if (rc == 3)
+ kmem_add_measure(name, len, addr);
+ else {
+ printk(KERN_INFO "kmem: error parsing request."
+ "(format: name length address)\n");
+ result = -EINVAL;
+ }
+out:
+ if (!data)
+ kfree(data);
+ return result;
+}
+
+static ssize_t kmem_read_template(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned char *tmp_buf;
+ int len;
+
+ if (!lastbuf)
+ return -EINVAL;
+
+ tmp_buf = kzalloc(2 * lastbuf_len, GFP_KERNEL);
+ if (!tmp_buf)
+ return -ENOMEM;
+
+ for (len = 0; len < lastbuf_len; len++)
+ sprintf((tmp_buf + len + len), "%02x", *(lastbuf + len));
+ return simple_read_from_buffer(buf, count, ppos, tmp_buf, len + len);
+}
+
+const static struct file_operations kmem_template_ops = {
+ .write = kmem_write_template,
+ .read = kmem_read_template
+};
+
+static struct dentry *kmem_template;
+
+static int __init init_kmem_template(void)
+{
+
+ printk(KERN_INFO "%s: \n", __func__);
+ integrity_register_template("kmem", &kmem_ops);
+
+ kmem_template = securityfs_create_file("kmem-template",
+ S_IRUSR | S_IRGRP | S_IWUSR,
+ NULL, NULL, &kmem_template_ops);
+ return 0;
+}
+
+static void __exit cleanup_kmem_template(void)
+{
+ printk(KERN_INFO "%s\n", __FUNCTION__);
+ integrity_unregister_template("kmem");
+
+ securityfs_remove(kmem_template);
+}
+
+module_init(init_kmem_template);
+module_exit(cleanup_kmem_template);
+
+MODULE_LICENSE("GPL");
Index: ltp-base-20080531/testcases/kernel/security/integrity/ima/kmem/kmem-test.sh
===================================================================
--- /dev/null
+++ ltp-base-20080531/testcases/kernel/security/integrity/ima/kmem/kmem-test.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright (C) 2008 IBM Corporation
+# Author: Mimi Zohar <zohar@us.ibm.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.
+
+# Load kmem-template, if not already loaded
+# Collect and store memory measurement
+# Verify the memory measurement contained in the ascii measurement list.
+
+lsmod | grep kmem_template > /dev/null
+if [ $? != 0 ]; then
+ insmod ./kmem-template.ko
+fi
+
+if [ ! -f /proc/kallsyms ]; then
+ echo 'kernel built without CONFIG_KALLSYMS'
+ exit 1
+fi
+proc_root=`cat /proc/kallsyms | grep 'D proc_root' | sed 's/ .*//'`
+echo 'proc_root 84' $proc_root > /sys/kernel/security/kmem-template
+
+# calculate and search for kmem hash in the ascii measurement list
+hash=`cat /sys/kernel/security/kmem-template | ../tools/hex2bin | sha1sum | sed 's/ -//'`
+`grep $hash /sys/kernel/security/ima/ascii_runtime_measurements > /dev/null`
+exit $?


\
 
 \ /
  Last update: 2008-07-08 00:07    [W:0.057 / U:0.412 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site