e9d93b7e28
Before opensource these patches a kernel revision different from the available in upstream was used. This changes recreates the patches to use a valid revision. Story: 2002964 Task: 22967 Change-Id: I424e928571ded42d2b768e1dbb1f87e8fb9aa847 Required-By: https://review.openstack.org/#/c/583016/ Signed-off-by: Erich Cordoba <erich.cordoba.malibran@intel.com> Signed-off-by: Scott Little <scott.little@windriver.com>
1323 lines
44 KiB
Diff
1323 lines
44 KiB
Diff
From 7e956b974091563edc1b4f5a7646f4d8dff07ee5 Mon Sep 17 00:00:00 2001
|
|
From: Kam Nasim <kam.nasim@windriver.com>
|
|
Date: Fri, 8 Sep 2017 16:34:25 -0400
|
|
Subject: [PATCH] US101216: IMA out-of-tree modules for Titanium Kernel
|
|
|
|
Build a kcompat layer and the ability to build out the Integrity and IMA
|
|
Kernel modules against a 3.10 Linux Kernel (CentOS v7.3)
|
|
---
|
|
Makefile | 107 ++++++++++++++++-
|
|
common.mk | 330 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
digsig.c | 35 ++++--
|
|
digsig_asymmetric.c | 22 +++-
|
|
iint.c | 52 +++++++--
|
|
ima/Makefile | 8 +-
|
|
ima/ima.h | 9 +-
|
|
ima/ima_api.c | 14 +--
|
|
ima/ima_appraise.c | 42 ++++---
|
|
ima/ima_fs.c | 4 +
|
|
ima/ima_init.c | 4 +-
|
|
ima/ima_main.c | 40 +++++--
|
|
ima/ima_policy.c | 32 ++++-
|
|
integrity.h | 9 +-
|
|
integrity_audit.c | 17 ++-
|
|
kcompat.h | 34 ++++++
|
|
16 files changed, 677 insertions(+), 82 deletions(-)
|
|
create mode 100644 common.mk
|
|
create mode 100644 kcompat.h
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
index 8d1f4bf..022a1b7 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,3 +1,7 @@
|
|
+
|
|
+ifneq ($(KERNELRELEASE),)
|
|
+# kbuild part of makefile
|
|
+
|
|
#
|
|
# Makefile for caching inode integrity data (iint)
|
|
#
|
|
@@ -11,5 +15,104 @@ integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
|
|
|
|
subdir-$(CONFIG_IMA) += ima
|
|
obj-$(CONFIG_IMA) += ima/
|
|
-subdir-$(CONFIG_EVM) += evm
|
|
-obj-$(CONFIG_EVM) += evm/
|
|
+
|
|
+else # ifneq($(KERNELRELEASE),)
|
|
+# normal makefile
|
|
+
|
|
+# driver will be provided by the spec file
|
|
+DRIVER=
|
|
+
|
|
+ifeq (,$(wildcard common.mk))
|
|
+ $(error Cannot find common.mk build rules)
|
|
+else
|
|
+ include common.mk
|
|
+endif
|
|
+
|
|
+###############
|
|
+# Build rules #
|
|
+###############
|
|
+
|
|
+# Standard compilation, with regular output
|
|
+default:
|
|
+ @+$(call kernelbuild,modules)
|
|
+
|
|
+# Noisy output, for extra debugging
|
|
+noisy:
|
|
+ @+$(call kernelbuild,modules,V=1)
|
|
+
|
|
+# Silence any output generated
|
|
+silent:
|
|
+ @+$(call kernelbuild,modules,>/dev/null)
|
|
+
|
|
+# Enable higher warning level
|
|
+checkwarnings: clean
|
|
+ @+$(call kernelbuild,modules,W=1)
|
|
+
|
|
+# Run sparse static analyzer
|
|
+sparse: clean
|
|
+ @+$(call kernelbuild,modules,C=2 CF="-D__CHECK_ENDIAN__ -Wbitwise -Wcontext")
|
|
+
|
|
+# Run coccicheck static analyzer
|
|
+ccc: clean
|
|
+ @+$(call kernelbuild,modules,coccicheck MODE=report)
|
|
+
|
|
+# Install the modules
|
|
+install: default
|
|
+ @echo "Installing modules..."
|
|
+ @+$(call kernelbuild,modules_install)
|
|
+ @echo "Running depmod..."
|
|
+ @$(call cmd_depmod)
|
|
+ifeq (${cmd_initrd},)
|
|
+ @echo "Unable to update initrd. You may need to do this manually."
|
|
+else
|
|
+ @echo "Updating initrd..."
|
|
+ -@$(call cmd_initrd)
|
|
+endif
|
|
+
|
|
+# Target used by rpmbuild spec file
|
|
+rpm: default
|
|
+ @install -D -m 644 ${DRIVER}.ko ${INSTALL_MOD_PATH}/lib/modules/${KVER}/${INSTALL_MOD_DIR}/${DRIVER}.ko
|
|
+
|
|
+uninstall:
|
|
+ rm -f ${INSTALL_MOD_PATH}/lib/modules/${KVER}/${INSTALL_MOD_DIR}/${DRIVER}.ko;
|
|
+ $(call cmd_depmod)
|
|
+ifeq (${cmd_initrd},)
|
|
+ @echo "Unable to update initrd. You may need to do this manually."
|
|
+else
|
|
+ @echo "Updating initrd..."
|
|
+ -@$(call cmd_initrd)
|
|
+endif
|
|
+
|
|
+########
|
|
+# Help #
|
|
+########
|
|
+help:
|
|
+ @echo 'Cleaning targets:'
|
|
+ @echo ' clean - Clean files generated by kernel module build'
|
|
+ @echo 'Build targets:'
|
|
+ @echo ' default - Build module(s) with standard verbosity'
|
|
+ @echo ' noisy - Build module(s) with V=1 verbosity -- very noisy'
|
|
+ @echo ' silent - Build module(s), squelching all output'
|
|
+ @echo 'Static Analysis:'
|
|
+ @echo ' checkwarnings - Clean, then build module(s) with W=1 warnings enabled'
|
|
+ @echo ' sparse - Clean, then check module(s) using sparse'
|
|
+ @echo ' ccc - Clean, then check module(s) using coccicheck'
|
|
+ @echo 'Other targets:'
|
|
+ @echo ' install - Build then install the module(s)'
|
|
+ @echo ' uninstall - Uninstall the module(s)'
|
|
+ @echo ' help - Display this help message'
|
|
+ @echo 'Variables:'
|
|
+ @echo ' LINUX_VERSION - Debug tool to force kernel LINUX_VERSION_CODE. Use at your own risk.'
|
|
+ @echo ' W=N - Kernel variable for setting warning levels'
|
|
+ @echo ' V=N - Kernel variable for setting output verbosity'
|
|
+ @echo ' INSTALL_MOD_PATH - Add prefix for the module and manpage installation path'
|
|
+ @echo ' INSTALL_MOD_DIR - Use module directory other than updates/security/integrity/${DRIVER}'
|
|
+ @echo ' KSRC - Specifies the full path to the kernel tree to build against'
|
|
+ @echo ' Other variables may be available for tuning make process, see'
|
|
+ @echo ' Kernel Kbuild documentation for more information'
|
|
+
|
|
+.PHONY: default noisy clean silent sparse ccc install uninstall help
|
|
+
|
|
+endif # ifneq($(KERNELRELEASE),)
|
|
+
|
|
+
|
|
diff --git a/common.mk b/common.mk
|
|
new file mode 100644
|
|
index 0000000..3541284
|
|
--- /dev/null
|
|
+++ b/common.mk
|
|
@@ -0,0 +1,330 @@
|
|
+################################################################################
|
|
+#
|
|
+# Linux IMA subsystem
|
|
+# Copyright(c) 2013 - 2017 Intel Corporation.
|
|
+# Copyright (c) 2017 Wind River Systems, Inc.
|
|
+#
|
|
+# This program is free software; you can redistribute it and/or modify it
|
|
+# under the terms and conditions of the GNU General Public License,
|
|
+# version 2, as published by the Free Software Foundation.
|
|
+#
|
|
+# This program is distributed in the hope it will be useful, but WITHOUT
|
|
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
+# more details.
|
|
+#
|
|
+# The full GNU General Public License is included in this distribution in
|
|
+# the file called "COPYING".
|
|
+#
|
|
+# Contact Information:
|
|
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
|
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
|
+################################################################################
|
|
+
|
|
+
|
|
+# common Makefile rules useful for out-of-tree Linux driver builds
|
|
+#
|
|
+# Usage: include common.mk
|
|
+#
|
|
+# After including, you probably want to add a minimum_kver_check call
|
|
+#
|
|
+# Required Variables:
|
|
+# DRIVER
|
|
+# -- Set to the lowercase driver name
|
|
+
|
|
+#####################
|
|
+# Helpful functions #
|
|
+#####################
|
|
+
|
|
+readlink = $(shell readlink -f ${1})
|
|
+
|
|
+# helper functions for converting kernel version to version codes
|
|
+get_kver = $(or $(word ${2},$(subst ., ,${1})),0)
|
|
+get_kvercode = $(shell [ "${1}" -ge 0 -a "${1}" -le 255 2>/dev/null ] && \
|
|
+ [ "${2}" -ge 0 -a "${2}" -le 255 2>/dev/null ] && \
|
|
+ [ "${3}" -ge 0 -a "${3}" -le 255 2>/dev/null ] && \
|
|
+ printf %d $$(( ( ${1} << 16 ) + ( ${2} << 8 ) + ( ${3} ) )) )
|
|
+
|
|
+################
|
|
+# depmod Macro #
|
|
+################
|
|
+
|
|
+cmd_depmod = /sbin/depmod $(if ${SYSTEM_MAP_FILE},-e -F ${SYSTEM_MAP_FILE}) \
|
|
+ $(if $(strip ${INSTALL_MOD_PATH}),-b ${INSTALL_MOD_PATH}) \
|
|
+ -a ${KVER}
|
|
+
|
|
+################
|
|
+# dracut Macro #
|
|
+################
|
|
+
|
|
+cmd_initrd := $(shell \
|
|
+ if which dracut > /dev/null 2>&1 ; then \
|
|
+ echo "dracut --force"; \
|
|
+ elif which update-initramfs > /dev/null 2>&1 ; then \
|
|
+ echo "update-initramfs -u"; \
|
|
+ fi )
|
|
+
|
|
+#####################
|
|
+# Environment tests #
|
|
+#####################
|
|
+
|
|
+DRIVER_UPPERCASE := $(shell echo ${DRIVER} | tr "[:lower:]" "[:upper:]" )
|
|
+
|
|
+ifeq (,${BUILD_KERNEL})
|
|
+BUILD_KERNEL=$(shell uname -r)
|
|
+endif
|
|
+
|
|
+# Kernel Search Path
|
|
+# All the places we look for kernel source
|
|
+KSP := /lib/modules/${BUILD_KERNEL}/source \
|
|
+ /lib/modules/${BUILD_KERNEL}/build \
|
|
+ /usr/src/linux-${BUILD_KERNEL} \
|
|
+ /usr/src/linux-$(${BUILD_KERNEL} | sed 's/-.*//') \
|
|
+ /usr/src/kernel-headers-${BUILD_KERNEL} \
|
|
+ /usr/src/kernel-source-${BUILD_KERNEL} \
|
|
+ /usr/src/linux-$(${BUILD_KERNEL} | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \
|
|
+ /usr/src/linux \
|
|
+ /usr/src/kernels/${BUILD_KERNEL} \
|
|
+ /usr/src/kernels
|
|
+
|
|
+# prune the list down to only values that exist and have an include/linux
|
|
+# sub-directory. We can't use include/config because some older kernels don't
|
|
+# have this.
|
|
+test_dir = $(shell [ -e ${dir}/include/linux ] && echo ${dir})
|
|
+KSP := $(foreach dir, ${KSP}, ${test_dir})
|
|
+
|
|
+# we will use this first valid entry in the search path
|
|
+ifeq (,${KSRC})
|
|
+ KSRC := $(firstword ${KSP})
|
|
+endif
|
|
+
|
|
+ifeq (,${KSRC})
|
|
+ $(warning *** Kernel header files not in any of the expected locations.)
|
|
+ $(warning *** Install the appropriate kernel development package, e.g.)
|
|
+ $(error kernel-devel, for building kernel modules and try again)
|
|
+else
|
|
+ifeq (/lib/modules/${BUILD_KERNEL}/source, ${KSRC})
|
|
+ KOBJ := /lib/modules/${BUILD_KERNEL}/build
|
|
+else
|
|
+ KOBJ := ${KSRC}
|
|
+endif
|
|
+endif
|
|
+
|
|
+# Version file Search Path
|
|
+VSP := ${KOBJ}/include/generated/utsrelease.h \
|
|
+ ${KOBJ}/include/linux/utsrelease.h \
|
|
+ ${KOBJ}/include/linux/version.h \
|
|
+ ${KOBJ}/include/generated/uapi/linux/version.h \
|
|
+ /boot/vmlinuz.version.h
|
|
+
|
|
+# Config file Search Path
|
|
+CSP := ${KOBJ}/include/generated/autoconf.h \
|
|
+ ${KOBJ}/include/linux/autoconf.h \
|
|
+ /boot/vmlinuz.autoconf.h
|
|
+
|
|
+# System.map Search Path (for depmod)
|
|
+MSP := ${KSRC}/System.map \
|
|
+ /boot/System.map-${BUILD_KERNEL}
|
|
+
|
|
+# prune the lists down to only files that exist
|
|
+test_file = $(shell [ -f ${file} ] && echo ${file})
|
|
+VSP := $(foreach file, ${VSP}, ${test_file})
|
|
+CSP := $(foreach file, ${CSP}, ${test_file})
|
|
+MSP := $(foreach file, ${MSP}, ${test_file})
|
|
+
|
|
+
|
|
+# and use the first valid entry in the Search Paths
|
|
+ifeq (,${VERSION_FILE})
|
|
+ VERSION_FILE := $(firstword ${VSP})
|
|
+endif
|
|
+
|
|
+ifeq (,${CONFIG_FILE})
|
|
+ CONFIG_FILE := $(firstword ${CSP})
|
|
+endif
|
|
+
|
|
+ifeq (,${SYSTEM_MAP_FILE})
|
|
+ SYSTEM_MAP_FILE := $(firstword ${MSP})
|
|
+endif
|
|
+
|
|
+ifeq (,$(wildcard ${VERSION_FILE}))
|
|
+ $(error Linux kernel source not configured - missing version header file)
|
|
+endif
|
|
+
|
|
+ifeq (,$(wildcard ${CONFIG_FILE}))
|
|
+ $(error Linux kernel source not configured - missing autoconf.h)
|
|
+endif
|
|
+
|
|
+ifeq (,$(wildcard ${SYSTEM_MAP_FILE}))
|
|
+ $(warning Missing System.map file - depmod will not check for missing symbols)
|
|
+endif
|
|
+
|
|
+#######################
|
|
+# Linux Version Setup #
|
|
+#######################
|
|
+
|
|
+# The following command line parameter is intended for development of KCOMPAT
|
|
+# against upstream kernels such as net-next which have broken or non-updated
|
|
+# version codes in their Makefile. They are intended for debugging and
|
|
+# development purpose only so that we can easily test new KCOMPAT early. If you
|
|
+# don't know what this means, you do not need to set this flag. There is no
|
|
+# arcane magic here.
|
|
+
|
|
+# Convert LINUX_VERSION into LINUX_VERSION_CODE
|
|
+ifneq (${LINUX_VERSION},)
|
|
+ LINUX_VERSION_CODE=$(call get_kvercode,$(call get_kver,${LINUX_VERSION},1),$(call get_kver,${LINUX_VERSION},2),$(call get_kver,${LINUX_VERSION},3))
|
|
+endif
|
|
+
|
|
+# Honor LINUX_VERSION_CODE
|
|
+ifneq (${LINUX_VERSION_CODE},)
|
|
+ $(warning Forcing target kernel to build with LINUX_VERSION_CODE of ${LINUX_VERSION_CODE}$(if ${LINUX_VERSION}, from LINUX_VERSION=${LINUX_VERSION}). Do this at your own risk.)
|
|
+ KVER_CODE := ${LINUX_VERSION_CODE}
|
|
+ EXTRA_CFLAGS += -DLINUX_VERSION_CODE=${LINUX_VERSION_CODE}
|
|
+endif
|
|
+
|
|
+# Determine SLE_LOCALVERSION_CODE for SuSE SLE >= 11 (needed by kcompat)
|
|
+# This assumes SuSE will continue setting CONFIG_LOCALVERSION to the string
|
|
+# appended to the stable kernel version on which their kernel is based with
|
|
+# additional versioning information (up to 3 numbers), a possible abbreviated
|
|
+# git SHA1 commit id and a kernel type, e.g. CONFIG_LOCALVERSION=-1.2.3-default
|
|
+# or CONFIG_LOCALVERSION=-999.gdeadbee-default
|
|
+ifeq (1,$(shell ${CC} -E -dM ${CONFIG_FILE} 2> /dev/null |\
|
|
+ grep -m 1 CONFIG_SUSE_KERNEL | awk '{ print $$3 }'))
|
|
+
|
|
+ifneq (10,$(shell ${CC} -E -dM ${CONFIG_FILE} 2> /dev/null |\
|
|
+ grep -m 1 CONFIG_SLE_VERSION | awk '{ print $$3 }'))
|
|
+
|
|
+ LOCALVERSION := $(shell ${CC} -E -dM ${CONFIG_FILE} 2> /dev/null |\
|
|
+ grep -m 1 CONFIG_LOCALVERSION | awk '{ print $$3 }' |\
|
|
+ cut -d'-' -f2 | sed 's/\.g[[:xdigit:]]\{7\}//')
|
|
+ LOCALVER_A := $(shell echo ${LOCALVERSION} | cut -d'.' -f1)
|
|
+ LOCALVER_B := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f2)
|
|
+ LOCALVER_C := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f3)
|
|
+ SLE_LOCALVERSION_CODE := $(shell expr ${LOCALVER_A} \* 65536 + \
|
|
+ 0${LOCALVER_B} \* 256 + 0${LOCALVER_C})
|
|
+ EXTRA_CFLAGS += -DSLE_LOCALVERSION_CODE=${SLE_LOCALVERSION_CODE}
|
|
+endif
|
|
+endif
|
|
+
|
|
+EXTRA_CFLAGS += ${CFLAGS_EXTRA}
|
|
+
|
|
+# get the kernel version - we use this to find the correct install path
|
|
+KVER := $(shell ${CC} ${EXTRA_CFLAGS} -E -dM ${VERSION_FILE} | grep UTS_RELEASE | \
|
|
+ awk '{ print $$3 }' | sed 's/\"//g')
|
|
+
|
|
+# assume source symlink is the same as build, otherwise adjust KOBJ
|
|
+ifneq (,$(wildcard /lib/modules/${KVER}/build))
|
|
+ ifneq (${KSRC},$(call readlink,/lib/modules/${KVER}/build))
|
|
+ KOBJ=/lib/modules/${KVER}/build
|
|
+ endif
|
|
+endif
|
|
+
|
|
+ifeq (${KVER_CODE},)
|
|
+ KVER_CODE := $(shell ${CC} ${EXTRA_CFLAGS} -E -dM ${VSP} 2> /dev/null |\
|
|
+ grep -m 1 LINUX_VERSION_CODE | awk '{ print $$3 }' | sed 's/\"//g')
|
|
+endif
|
|
+
|
|
+# minimum_kver_check
|
|
+#
|
|
+# helper function to provide uniform output for different drivers to abort the
|
|
+# build based on kernel version check. Usage: "$(call minimum_kver_check,2,6,XX)".
|
|
+define _minimum_kver_check
|
|
+ifeq (0,$(shell [ ${KVER_CODE} -lt $(call get_kvercode,${1},${2},${3}) ]; echo "$$?"))
|
|
+ $$(warning *** Aborting the build.)
|
|
+ $$(error This driver is not supported on kernel versions older than ${1}.${2}.${3})
|
|
+endif
|
|
+endef
|
|
+minimum_kver_check = $(eval $(call _minimum_kver_check,${1},${2},${3}))
|
|
+
|
|
+################
|
|
+# Manual Pages #
|
|
+################
|
|
+
|
|
+MANSECTION = 7
|
|
+
|
|
+ifeq (,${MANDIR})
|
|
+ # find the best place to install the man page
|
|
+ MANPATH := $(shell (manpath 2>/dev/null || echo $MANPATH) | sed 's/:/ /g')
|
|
+ ifneq (,${MANPATH})
|
|
+ # test based on inclusion in MANPATH
|
|
+ test_dir = $(findstring ${dir}, ${MANPATH})
|
|
+ else
|
|
+ # no MANPATH, test based on directory existence
|
|
+ test_dir = $(shell [ -e ${dir} ] && echo ${dir})
|
|
+ endif
|
|
+ # our preferred install path
|
|
+ # should /usr/local/man be in here ?
|
|
+ MANDIR := /usr/share/man /usr/man
|
|
+ MANDIR := $(foreach dir, ${MANDIR}, ${test_dir})
|
|
+ MANDIR := $(firstword ${MANDIR})
|
|
+endif
|
|
+ifeq (,${MANDIR})
|
|
+ # fallback to /usr/man
|
|
+ MANDIR := /usr/man
|
|
+endif
|
|
+
|
|
+####################
|
|
+# CCFLAGS variable #
|
|
+####################
|
|
+
|
|
+# set correct CCFLAGS variable for kernels older than 2.6.24
|
|
+ifeq (0,$(shell [ ${KVER_CODE} -lt $(call get_kvercode,2,6,24) ]; echo $$?))
|
|
+CCFLAGS_VAR := EXTRA_CFLAGS
|
|
+else
|
|
+CCFLAGS_VAR := ccflags-y
|
|
+endif
|
|
+
|
|
+#################
|
|
+# KBUILD_OUTPUT #
|
|
+#################
|
|
+
|
|
+# Only set KBUILD_OUTPUT if KOBJ differs from KSRC
|
|
+ifneq (${KSRC},${KOBJ})
|
|
+export KBUILD_OUTPUT ?= ${KOBJ}
|
|
+endif
|
|
+
|
|
+############################
|
|
+# Module Install Directory #
|
|
+############################
|
|
+
|
|
+# Default to using updates/security/integrity/ path, since depmod since
|
|
+# v3.1 defaults to checking updates folder first, and only checking kernels/
|
|
+# and extra afterwards. We use updates instead of kernel/* due to desire to
|
|
+# prevent over-writing built-in modules files.
|
|
+export INSTALL_MOD_DIR ?= updates/security/integrity/
|
|
+
|
|
+
|
|
+######################
|
|
+# Kernel Build Macro #
|
|
+######################
|
|
+
|
|
+# kernel build function
|
|
+# ${1} is the kernel build target
|
|
+# ${2} may contain any extra rules to pass directly to the sub-make process
|
|
+#
|
|
+# This function is expected to be executed by
|
|
+# @+$(call kernelbuild,<target>,<extra parameters>)
|
|
+# from within a Makefile recipe.
|
|
+#
|
|
+# The following variables are expected to be defined for its use:
|
|
+# GCC_I_SYS -- if set it will enable use of gcc-i-sys.sh wrapper to use -isystem
|
|
+# CCFLAGS_VAR -- the CCFLAGS variable to set extra CFLAGS
|
|
+# EXTRA_CFLAGS -- a set of extra CFLAGS to pass into the ccflags-y variable
|
|
+# KSRC -- the location of the kernel source tree to build against
|
|
+# DRIVER_UPPERCASE -- the uppercase name of the kernel module, set from DRIVER
|
|
+#
|
|
+# N.B: We specify all of our hash, template and PCR choices
|
|
+# right when we build the option. This is because the kernel module
|
|
+# will be signed, and we will prevent users from modifying these
|
|
+# options at runtime and reloading the module
|
|
+kernelbuild = ${MAKE} $(if ${GCC_I_SYS},CC="${GCC_I_SYS}") \
|
|
+ ${CCFLAGS_VAR}="${EXTRA_CFLAGS}" \
|
|
+ -C "${KSRC}" \
|
|
+ CONFIG_INTEGRITY=m \
|
|
+ CONFIG_INTEGRITY_AUDIT=y \
|
|
+ CONFIG_INTEGRITY_SIGNATURE=y \
|
|
+ CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y \
|
|
+ CONFIG_IMA=m \
|
|
+ CONFIG_${DRIVER_UPPERCASE}=m \
|
|
+ modules \
|
|
+ M="${CURDIR}" \
|
|
+ ${2} ${1}
|
|
diff --git a/digsig.c b/digsig.c
|
|
index 106e855..f850ef7 100644
|
|
--- a/digsig.c
|
|
+++ b/digsig.c
|
|
@@ -37,9 +37,9 @@ static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
|
|
};
|
|
|
|
#ifdef CONFIG_INTEGRITY_TRUSTED_KEYRING
|
|
-static bool init_keyring __initdata = true;
|
|
+static bool init_keyring = true;
|
|
#else
|
|
-static bool init_keyring __initdata;
|
|
+static bool init_keyring;
|
|
#endif
|
|
|
|
#ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
|
|
@@ -77,39 +77,43 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
|
|
|
return -EOPNOTSUPP;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(integrity_digsig_verify);
|
|
|
|
-int __init integrity_init_keyring(const unsigned int id)
|
|
+int integrity_init_keyring(const unsigned int id)
|
|
{
|
|
const struct cred *cred = current_cred();
|
|
- struct key_restriction *restriction;
|
|
int err = 0;
|
|
|
|
- if (!init_keyring)
|
|
+ if (!init_keyring) {
|
|
+ /* WRS: This external keyring is created inside
|
|
+ * the Kernel as a trusted keyring for which
|
|
+ * a search reference is available
|
|
+ */
|
|
+ keyring[id] = ima_keyring;
|
|
return 0;
|
|
-
|
|
- restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
|
|
- if (!restriction)
|
|
- return -ENOMEM;
|
|
-
|
|
- restriction->check = restrict_link_to_ima;
|
|
+ }
|
|
|
|
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
|
|
KGIDT_INIT(0), cred,
|
|
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
|
KEY_USR_VIEW | KEY_USR_READ |
|
|
KEY_USR_WRITE | KEY_USR_SEARCH),
|
|
- KEY_ALLOC_NOT_IN_QUOTA,
|
|
- restriction, NULL);
|
|
- if (IS_ERR(keyring[id])) {
|
|
+ KEY_ALLOC_NOT_IN_QUOTA, NULL);
|
|
+
|
|
+ if (!IS_ERR(keyring[id])) {
|
|
+ set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
|
|
+ } else {
|
|
err = PTR_ERR(keyring[id]);
|
|
pr_info("Can't allocate %s keyring (%d)\n",
|
|
keyring_name[id], err);
|
|
keyring[id] = NULL;
|
|
}
|
|
+ init_keyring = false;
|
|
return err;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(integrity_init_keyring);
|
|
|
|
-int __init integrity_load_x509(const unsigned int id, const char *path)
|
|
+int integrity_load_x509(const unsigned int id, const char *path)
|
|
{
|
|
key_ref_t key;
|
|
char *data;
|
|
diff --git a/digsig_asymmetric.c b/digsig_asymmetric.c
|
|
index 80052ed..1753b60 100644
|
|
--- a/digsig_asymmetric.c
|
|
+++ b/digsig_asymmetric.c
|
|
@@ -34,6 +34,7 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
|
|
|
|
pr_debug("key search: \"%s\"\n", name);
|
|
|
|
+#ifdef CONFIG_IMA_MOK_KEYRING
|
|
key = get_ima_blacklist_keyring();
|
|
if (key) {
|
|
key_ref_t kref;
|
|
@@ -45,6 +46,7 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
|
|
return ERR_PTR(-EKEYREJECTED);
|
|
}
|
|
}
|
|
+#endif
|
|
|
|
if (keyring) {
|
|
/* search in specific keyring */
|
|
@@ -95,7 +97,11 @@ int asymmetric_verify(struct key *keyring, const char *sig,
|
|
if (siglen != __be16_to_cpu(hdr->sig_size))
|
|
return -EBADMSG;
|
|
|
|
+#if ( LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0) )
|
|
+ if (hdr->hash_algo >= PKEY_HASH__LAST)
|
|
+#else
|
|
if (hdr->hash_algo >= HASH_ALGO__LAST)
|
|
+#endif
|
|
return -ENOPKG;
|
|
|
|
key = request_asymmetric_key(keyring, __be32_to_cpu(hdr->keyid));
|
|
@@ -103,14 +109,24 @@ int asymmetric_verify(struct key *keyring, const char *sig,
|
|
return PTR_ERR(key);
|
|
|
|
memset(&pks, 0, sizeof(pks));
|
|
-
|
|
- pks.pkey_algo = "rsa";
|
|
- pks.hash_algo = hash_algo_name[hdr->hash_algo];
|
|
+
|
|
pks.digest = (u8 *)data;
|
|
pks.digest_size = datalen;
|
|
+#if ( LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0) )
|
|
+ pks.pkey_algo = PKEY_ALGO_RSA;
|
|
+ pks.pkey_hash_algo = hdr->hash_algo;
|
|
+ pks.nr_mpi =1;
|
|
+ pks.rsa.s = mpi_read_raw_data(hdr->sig, siglen);
|
|
+ if(pks.rsa.s)
|
|
+ ret = verify_signature(key, &pks);
|
|
+ mpi_free(pks.rsa.s);
|
|
+#else
|
|
+ pks.pkey_algo = "rsa";
|
|
+ pks.hash_algo = hash_algo_name[hdr->hash_algo];
|
|
pks.s = hdr->sig;
|
|
pks.s_size = siglen;
|
|
ret = verify_signature(key, &pks);
|
|
+#endif
|
|
key_put(key);
|
|
pr_debug("%s() = %d\n", __func__, ret);
|
|
return ret;
|
|
diff --git a/iint.c b/iint.c
|
|
index c710d22..83405a1 100644
|
|
--- a/iint.c
|
|
+++ b/iint.c
|
|
@@ -27,6 +27,9 @@ static struct rb_root integrity_iint_tree = RB_ROOT;
|
|
static DEFINE_RWLOCK(integrity_iint_lock);
|
|
static struct kmem_cache *iint_cache __read_mostly;
|
|
|
|
+static struct integrity_iint_cache * (*integrity_inode_get_kernel)(struct inode *);
|
|
+static void (*integrity_inode_free_kernel)(struct inode *);
|
|
+
|
|
/*
|
|
* __integrity_iint_find - return the iint associated with an inode
|
|
*/
|
|
@@ -67,6 +70,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
|
|
|
|
return iint;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(integrity_iint_find);
|
|
|
|
static void iint_free(struct integrity_iint_cache *iint)
|
|
{
|
|
@@ -90,7 +94,7 @@ static void iint_free(struct integrity_iint_cache *iint)
|
|
*
|
|
* Caller must lock i_mutex
|
|
*/
|
|
-struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
|
|
+static struct integrity_iint_cache *__integrity_inode_get(struct inode *inode)
|
|
{
|
|
struct rb_node **p;
|
|
struct rb_node *node, *parent = NULL;
|
|
@@ -100,7 +104,7 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
|
|
if (iint)
|
|
return iint;
|
|
|
|
- iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
|
|
+ iint = kmem_cache_alloc(iint_cache, GFP_KERNEL);
|
|
if (!iint)
|
|
return NULL;
|
|
|
|
@@ -110,7 +114,7 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
|
|
while (*p) {
|
|
parent = *p;
|
|
test_iint = rb_entry(parent, struct integrity_iint_cache,
|
|
- rb_node);
|
|
+ rb_node);
|
|
if (inode < test_iint->inode)
|
|
p = &(*p)->rb_left;
|
|
else
|
|
@@ -133,7 +137,7 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
|
|
*
|
|
* Free the integrity information(iint) associated with an inode.
|
|
*/
|
|
-void integrity_inode_free(struct inode *inode)
|
|
+static void __integrity_inode_free(struct inode *inode)
|
|
{
|
|
struct integrity_iint_cache *iint;
|
|
|
|
@@ -166,8 +170,21 @@ static void init_once(void *foo)
|
|
static int __init integrity_iintcache_init(void)
|
|
{
|
|
iint_cache =
|
|
- kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
|
|
- 0, SLAB_PANIC, init_once);
|
|
+ kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
|
|
+ 0, SLAB_PANIC, init_once);
|
|
+
|
|
+ /*
|
|
+ * stow away original Kernel references
|
|
+ * for these functions to assign back
|
|
+ * on deinit
|
|
+ */
|
|
+ integrity_inode_get_kernel = integrity_inode_get;
|
|
+ integrity_inode_free_kernel = integrity_inode_free;
|
|
+
|
|
+ integrity_inode_get = &__integrity_inode_get;
|
|
+ integrity_inode_free = &__integrity_inode_free;
|
|
+ pr_info("Initializing Integrity Base Module\n");
|
|
+
|
|
return 0;
|
|
}
|
|
security_initcall(integrity_iintcache_init);
|
|
@@ -186,18 +203,22 @@ int integrity_kernel_read(struct file *file, loff_t offset,
|
|
{
|
|
mm_segment_t old_fs;
|
|
char __user *buf = (char __user *)addr;
|
|
- ssize_t ret;
|
|
+ ssize_t ret = -EINVAL;
|
|
|
|
if (!(file->f_mode & FMODE_READ))
|
|
return -EBADF;
|
|
|
|
old_fs = get_fs();
|
|
set_fs(get_ds());
|
|
- ret = __vfs_read(file, buf, count, &offset);
|
|
+ if (file->f_op->read)
|
|
+ ret = file->f_op->read(file, buf, count, &offset);
|
|
+ else if (file->f_op->aio_read)
|
|
+ ret = do_sync_read(file, buf, count, &offset);
|
|
set_fs(old_fs);
|
|
|
|
return ret;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(integrity_kernel_read);
|
|
|
|
/*
|
|
* integrity_read_file - read entire file content into the buffer
|
|
@@ -259,3 +280,18 @@ void __init integrity_load_keys(void)
|
|
ima_load_x509();
|
|
evm_load_x509();
|
|
}
|
|
+
|
|
+static void __exit cleanup_integrity(void)
|
|
+{
|
|
+ /*
|
|
+ * assign back to default kernel definations
|
|
+ * for these dynamic functions
|
|
+ */
|
|
+ integrity_inode_get = integrity_inode_get_kernel;
|
|
+ integrity_inode_free = integrity_inode_free_kernel;
|
|
+}
|
|
+
|
|
+module_exit(cleanup_integrity);
|
|
+MODULE_DESCRIPTION("Integrity Base Driver");
|
|
+MODULE_LICENSE("GPL");
|
|
+
|
|
diff --git a/ima/Makefile b/ima/Makefile
|
|
index 29f198b..cdf918c 100644
|
|
--- a/ima/Makefile
|
|
+++ b/ima/Makefile
|
|
@@ -6,7 +6,7 @@
|
|
obj-$(CONFIG_IMA) += ima.o
|
|
|
|
ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
|
|
- ima_policy.o ima_template.o ima_template_lib.o
|
|
-ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
|
|
-ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
|
|
-obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
|
|
+ ima_policy.o ima_template.o ima_template_lib.o ima_appraise.o
|
|
+#ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
|
|
+#ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
|
|
+#obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
|
|
diff --git a/ima/ima.h b/ima/ima.h
|
|
index b563fbd..5492dda 100644
|
|
--- a/ima/ima.h
|
|
+++ b/ima/ima.h
|
|
@@ -17,6 +17,9 @@
|
|
#ifndef __LINUX_IMA_H
|
|
#define __LINUX_IMA_H
|
|
|
|
+// include kcompat layer
|
|
+#include "../kcompat.h"
|
|
+
|
|
#include <linux/types.h>
|
|
#include <linux/crypto.h>
|
|
#include <linux/fs.h>
|
|
@@ -155,6 +158,7 @@ unsigned long ima_get_binary_runtime_size(void);
|
|
int ima_init_template(void);
|
|
void ima_init_template_list(void);
|
|
|
|
+
|
|
/*
|
|
* used to protect h_table and sha_table
|
|
*/
|
|
@@ -242,7 +246,10 @@ enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
|
|
int xattr_len);
|
|
int ima_read_xattr(struct dentry *dentry,
|
|
struct evm_ima_xattr_data **xattr_value);
|
|
-
|
|
+void __ima_inode_post_setattr(struct dentry *dentry);
|
|
+int __ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
|
|
+ const void *xattr_value, size_t xattr_value_len);
|
|
+int __ima_inode_removexattr(struct dentry *dentry, const char *xattr_name);
|
|
#else
|
|
static inline int ima_appraise_measurement(enum ima_hooks func,
|
|
struct integrity_iint_cache *iint,
|
|
diff --git a/ima/ima_api.c b/ima/ima_api.c
|
|
index c2edba8..e14e9d0 100644
|
|
--- a/ima/ima_api.c
|
|
+++ b/ima/ima_api.c
|
|
@@ -307,11 +307,9 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
|
|
if (!ab)
|
|
return;
|
|
|
|
- audit_log_format(ab, "file=");
|
|
- audit_log_untrustedstring(ab, filename);
|
|
- audit_log_format(ab, " hash=");
|
|
+ audit_log_format(ab, "file=%s", filename);
|
|
snprintf(algo_hash, sizeof(algo_hash), "%s:%s", algo_name, hash);
|
|
- audit_log_untrustedstring(ab, algo_hash);
|
|
+ audit_log_format(ab, " hash=%s", algo_hash);
|
|
|
|
audit_log_task_info(ab, current);
|
|
audit_log_end(ab);
|
|
@@ -332,12 +330,12 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
|
|
const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
|
|
{
|
|
char *pathname = NULL;
|
|
-
|
|
- *pathbuf = __getname();
|
|
+ /* We will allow 11 spaces for ' (deleted)' to be appended */
|
|
+ *pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
|
|
if (*pathbuf) {
|
|
- pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
|
|
+ pathname = d_path(path, *pathbuf, PATH_MAX + 11);
|
|
if (IS_ERR(pathname)) {
|
|
- __putname(*pathbuf);
|
|
+ kfree(*pathbuf);
|
|
*pathbuf = NULL;
|
|
pathname = NULL;
|
|
}
|
|
diff --git a/ima/ima_appraise.c b/ima/ima_appraise.c
|
|
index 1fd9539..b0d4286 100644
|
|
--- a/ima/ima_appraise.c
|
|
+++ b/ima/ima_appraise.c
|
|
@@ -8,6 +8,9 @@
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 2 of the License.
|
|
*/
|
|
+
|
|
+#include "../kcompat.h"
|
|
+
|
|
#include <linux/module.h>
|
|
#include <linux/file.h>
|
|
#include <linux/fs.h>
|
|
@@ -58,10 +61,10 @@ static int ima_fix_xattr(struct dentry *dentry,
|
|
iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG;
|
|
iint->ima_hash->xattr.ng.algo = algo;
|
|
}
|
|
- rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
|
|
- &iint->ima_hash->xattr.data[offset],
|
|
- (sizeof(iint->ima_hash->xattr) - offset) +
|
|
- iint->ima_hash->length, 0);
|
|
+ rc = vfs_setxattr(dentry, XATTR_NAME_IMA,
|
|
+ &iint->ima_hash->xattr.data[offset],
|
|
+ (sizeof(iint->ima_hash->xattr) - offset) +
|
|
+ iint->ima_hash->length, 0);
|
|
return rc;
|
|
}
|
|
|
|
@@ -168,14 +171,14 @@ enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
|
|
int ima_read_xattr(struct dentry *dentry,
|
|
struct evm_ima_xattr_data **xattr_value)
|
|
{
|
|
- ssize_t ret;
|
|
+ struct inode *inode = d_backing_inode(dentry);
|
|
+ if (!inode->i_op->getxattr)
|
|
+ return 0;
|
|
|
|
- ret = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
|
|
- 0, GFP_NOFS);
|
|
- if (ret == -EOPNOTSUPP)
|
|
- ret = 0;
|
|
- return ret;
|
|
+ return vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
|
|
+ 0, GFP_NOFS);
|
|
}
|
|
+EXPORT_SYMBOL_GPL(ima_read_xattr);
|
|
|
|
/*
|
|
* ima_appraise_measurement - appraise file measurement
|
|
@@ -198,7 +201,7 @@ int ima_appraise_measurement(enum ima_hooks func,
|
|
enum integrity_status status = INTEGRITY_UNKNOWN;
|
|
int rc = xattr_len, hash_start = 0;
|
|
|
|
- if (!(inode->i_opflags & IOP_XATTR))
|
|
+ if (!inode->i_op->getxattr)
|
|
return INTEGRITY_UNKNOWN;
|
|
|
|
if (rc <= 0) {
|
|
@@ -214,7 +217,11 @@ int ima_appraise_measurement(enum ima_hooks func,
|
|
goto out;
|
|
}
|
|
|
|
+#ifdef CONFIG_EVM
|
|
status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint);
|
|
+#else
|
|
+ status = INTEGRITY_UNKNOWN; /* CONFIG_INTEGRITY */
|
|
+#endif
|
|
if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) {
|
|
if ((status == INTEGRITY_NOLABEL)
|
|
|| (status == INTEGRITY_NOXATTRS))
|
|
@@ -321,14 +328,14 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
|
|
* This function is called from notify_change(), which expects the caller
|
|
* to lock the inode's i_mutex.
|
|
*/
|
|
-void ima_inode_post_setattr(struct dentry *dentry)
|
|
+void __ima_inode_post_setattr(struct dentry *dentry)
|
|
{
|
|
struct inode *inode = d_backing_inode(dentry);
|
|
struct integrity_iint_cache *iint;
|
|
- int must_appraise;
|
|
+ int must_appraise, rc;
|
|
|
|
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|
|
- || !(inode->i_opflags & IOP_XATTR))
|
|
+ || !inode->i_op->removexattr)
|
|
return;
|
|
|
|
must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
|
|
@@ -341,7 +348,8 @@ void ima_inode_post_setattr(struct dentry *dentry)
|
|
iint->flags |= IMA_APPRAISE;
|
|
}
|
|
if (!must_appraise)
|
|
- __vfs_removexattr(dentry, XATTR_NAME_IMA);
|
|
+ rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA);
|
|
+ return;
|
|
}
|
|
|
|
/*
|
|
@@ -378,7 +386,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
|
|
return;
|
|
}
|
|
|
|
-int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
|
|
+int __ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
|
|
const void *xattr_value, size_t xattr_value_len)
|
|
{
|
|
const struct evm_ima_xattr_data *xvalue = xattr_value;
|
|
@@ -396,7 +404,7 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
|
|
return result;
|
|
}
|
|
|
|
-int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
|
|
+int __ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
|
|
{
|
|
int result;
|
|
|
|
diff --git a/ima/ima_fs.c b/ima/ima_fs.c
|
|
index ca303e5..e871955 100644
|
|
--- a/ima/ima_fs.c
|
|
+++ b/ima/ima_fs.c
|
|
@@ -274,6 +274,9 @@ static const struct file_operations ima_ascii_measurements_ops = {
|
|
|
|
static ssize_t ima_read_policy(char *path)
|
|
{
|
|
+#if ( LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0) )
|
|
+ return -EINVAL;
|
|
+#else
|
|
void *data;
|
|
char *datap;
|
|
loff_t size;
|
|
@@ -307,6 +310,7 @@ static ssize_t ima_read_policy(char *path)
|
|
return -EINVAL;
|
|
else
|
|
return pathlen;
|
|
+#endif
|
|
}
|
|
|
|
static ssize_t ima_write_policy(struct file *file, const char __user *buf,
|
|
diff --git a/ima/ima_init.c b/ima/ima_init.c
|
|
index 2967d49..0759c8c 100644
|
|
--- a/ima/ima_init.c
|
|
+++ b/ima/ima_init.c
|
|
@@ -117,7 +117,9 @@ int __init ima_init(void)
|
|
if (!ima_used_chip)
|
|
pr_info("No TPM chip found, activating TPM-bypass! (rc=%d)\n",
|
|
rc);
|
|
-
|
|
+ else
|
|
+ pr_info("TPM chip found, using TPM for aggregate measurements!\n");
|
|
+
|
|
rc = integrity_init_keyring(INTEGRITY_KEYRING_IMA);
|
|
if (rc)
|
|
return rc;
|
|
diff --git a/ima/ima_main.c b/ima/ima_main.c
|
|
index 2aebb79..5d6ba23 100644
|
|
--- a/ima/ima_main.c
|
|
+++ b/ima/ima_main.c
|
|
@@ -16,6 +16,10 @@
|
|
* implements the IMA hooks: ima_bprm_check, ima_file_mmap,
|
|
* and ima_file_check.
|
|
*/
|
|
+
|
|
+// include kcompat layer
|
|
+#include "../kcompat.h"
|
|
+
|
|
#include <linux/module.h>
|
|
#include <linux/file.h>
|
|
#include <linux/binfmts.h>
|
|
@@ -30,7 +34,10 @@
|
|
int ima_initialized;
|
|
|
|
#ifdef CONFIG_IMA_APPRAISE
|
|
-int ima_appraise = IMA_APPRAISE_ENFORCE;
|
|
+/*
|
|
+ * WRS: Set default appraise action as "log"
|
|
+ */
|
|
+int ima_appraise = IMA_APPRAISE_LOG;
|
|
#else
|
|
int ima_appraise;
|
|
#endif
|
|
@@ -140,7 +147,7 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
|
|
*
|
|
* Flag files that changed, based on i_version
|
|
*/
|
|
-void ima_file_free(struct file *file)
|
|
+static void __ima_file_free(struct file *file)
|
|
{
|
|
struct inode *inode = file_inode(file);
|
|
struct integrity_iint_cache *iint;
|
|
@@ -259,8 +266,7 @@ out_digsig:
|
|
rc = -EACCES;
|
|
kfree(xattr_value);
|
|
out_free:
|
|
- if (pathbuf)
|
|
- __putname(pathbuf);
|
|
+ kfree(pathbuf);
|
|
out:
|
|
inode_unlock(inode);
|
|
if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
|
|
@@ -279,7 +285,7 @@ out:
|
|
* On success return 0. On integrity appraisal error, assuming the file
|
|
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
|
|
*/
|
|
-int ima_file_mmap(struct file *file, unsigned long prot)
|
|
+static int __ima_file_mmap(struct file *file, unsigned long prot)
|
|
{
|
|
if (file && (prot & PROT_EXEC))
|
|
return process_measurement(file, NULL, 0, MAY_EXEC,
|
|
@@ -300,7 +306,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
|
|
* On success return 0. On integrity appraisal error, assuming the file
|
|
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
|
|
*/
|
|
-int ima_bprm_check(struct linux_binprm *bprm)
|
|
+static int __ima_bprm_check(struct linux_binprm *bprm)
|
|
{
|
|
return process_measurement(bprm->file, NULL, 0, MAY_EXEC,
|
|
BPRM_CHECK, 0);
|
|
@@ -316,13 +322,12 @@ int ima_bprm_check(struct linux_binprm *bprm)
|
|
* On success return 0. On integrity appraisal error, assuming the file
|
|
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
|
|
*/
|
|
-int ima_file_check(struct file *file, int mask, int opened)
|
|
+static int __ima_file_check(struct file *file, int mask, int opened)
|
|
{
|
|
return process_measurement(file, NULL, 0,
|
|
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
|
|
MAY_APPEND), FILE_CHECK, opened);
|
|
}
|
|
-EXPORT_SYMBOL_GPL(ima_file_check);
|
|
|
|
/**
|
|
* ima_post_path_mknod - mark as a new inode
|
|
@@ -346,6 +351,7 @@ void ima_post_path_mknod(struct dentry *dentry)
|
|
iint->flags |= IMA_NEW_FILE;
|
|
}
|
|
|
|
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,10,0) )
|
|
/**
|
|
* ima_read_file - pre-measure/appraise hook decision based on policy
|
|
* @file: pointer to the file to be measured/appraised/audit
|
|
@@ -415,10 +421,28 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
|
|
func = read_idmap[read_id] ?: FILE_CHECK;
|
|
return process_measurement(file, buf, size, MAY_READ, func, 0);
|
|
}
|
|
+#endif
|
|
|
|
static int __init init_ima(void)
|
|
{
|
|
int error;
|
|
+
|
|
+ /*
|
|
+ * On loading the module, map the kernel inline
|
|
+ * function calls (used by the FS layer) to
|
|
+ * function definations within the module.
|
|
+ *
|
|
+ * N.B: No specific unmapping (to Kernel default)
|
|
+ * required as IMA module cannot be removed (even forcebly),
|
|
+ * once it binds to the Kernel VFS layer
|
|
+ */
|
|
+ ima_bprm_check = &__ima_bprm_check;
|
|
+ ima_file_check = &__ima_file_check;
|
|
+ ima_file_free = &__ima_file_free;
|
|
+ ima_file_mmap = &__ima_file_mmap;
|
|
+ ima_inode_post_setattr = &__ima_inode_post_setattr;
|
|
+ ima_inode_setxattr = &__ima_inode_setxattr;
|
|
+ ima_inode_removexattr = &__ima_inode_removexattr;
|
|
|
|
ima_init_template_list();
|
|
hash_setup(CONFIG_IMA_DEFAULT_HASH);
|
|
diff --git a/ima/ima_policy.c b/ima/ima_policy.c
|
|
index aed47b7..dd52d98 100644
|
|
--- a/ima/ima_policy.c
|
|
+++ b/ima/ima_policy.c
|
|
@@ -85,7 +85,7 @@ struct ima_rule_entry {
|
|
* normal users can easily run the machine out of memory simply building
|
|
* and running executables.
|
|
*/
|
|
-static struct ima_rule_entry dont_measure_rules[] __ro_after_init = {
|
|
+static struct ima_rule_entry dont_measure_rules[] = {
|
|
{.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC},
|
|
{.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC},
|
|
{.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC},
|
|
@@ -96,10 +96,12 @@ static struct ima_rule_entry dont_measure_rules[] __ro_after_init = {
|
|
{.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
|
|
{.action = DONT_MEASURE, .fsmagic = CGROUP_SUPER_MAGIC,
|
|
.flags = IMA_FSMAGIC},
|
|
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,10,0) )
|
|
{.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}
|
|
+#endif
|
|
};
|
|
|
|
-static struct ima_rule_entry original_measurement_rules[] __ro_after_init = {
|
|
+static struct ima_rule_entry original_measurement_rules[] = {
|
|
{.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC,
|
|
.flags = IMA_FUNC | IMA_MASK},
|
|
{.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC,
|
|
@@ -111,7 +113,7 @@ static struct ima_rule_entry original_measurement_rules[] __ro_after_init = {
|
|
{.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
|
|
};
|
|
|
|
-static struct ima_rule_entry default_measurement_rules[] __ro_after_init = {
|
|
+static struct ima_rule_entry default_measurement_rules[] = {
|
|
{.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC,
|
|
.flags = IMA_FUNC | IMA_MASK},
|
|
{.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC,
|
|
@@ -127,7 +129,7 @@ static struct ima_rule_entry default_measurement_rules[] __ro_after_init = {
|
|
{.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC},
|
|
};
|
|
|
|
-static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
|
|
+static struct ima_rule_entry default_appraise_rules[] = {
|
|
{.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC},
|
|
{.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC},
|
|
{.action = DONT_APPRAISE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC},
|
|
@@ -137,7 +139,9 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
|
|
{.action = DONT_APPRAISE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC},
|
|
{.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC},
|
|
{.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
|
|
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,10,0) )
|
|
{.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC},
|
|
+#endif
|
|
{.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC},
|
|
#ifdef CONFIG_IMA_WRITE_POLICY
|
|
{.action = APPRAISE, .func = POLICY_CHECK,
|
|
@@ -249,7 +253,11 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
|
|
if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid))
|
|
return false;
|
|
if (rule->flags & IMA_EUID) {
|
|
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,10,0) )
|
|
if (has_capability_noaudit(current, CAP_SETUID)) {
|
|
+#else
|
|
+ if (capable_wrt_inode_uidgid(inode, CAP_SETUID) || capable(CAP_SETUID)) {
|
|
+#endif
|
|
if (!rule->uid_op(cred->euid, rule->uid)
|
|
&& !rule->uid_op(cred->suid, rule->uid)
|
|
&& !rule->uid_op(cred->uid, rule->uid))
|
|
@@ -556,16 +564,34 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
|
|
return result;
|
|
}
|
|
|
|
+static int ima_string_contains_hex(const char *string, size_t len)
|
|
+{
|
|
+ const unsigned char *p;
|
|
+ for (p = string; p < (const unsigned char *)string + len; p++) {
|
|
+ if (*p == '"' || *p < 0x21 || *p > 0x7e)
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static void ima_log_string_op(struct audit_buffer *ab, char *key, char *value,
|
|
bool (*rule_operator)(kuid_t, kuid_t))
|
|
{
|
|
- if (rule_operator == &uid_gt)
|
|
- audit_log_format(ab, "%s>", key);
|
|
- else if (rule_operator == &uid_lt)
|
|
- audit_log_format(ab, "%s<", key);
|
|
- else
|
|
- audit_log_format(ab, "%s=", key);
|
|
- audit_log_untrustedstring(ab, value);
|
|
+ if (ima_string_contains_hex(value, strlen(value))) {
|
|
+ if (rule_operator == &uid_gt)
|
|
+ audit_log_format(ab, "%s>(contains hex)%s", key, value);
|
|
+ else if (rule_operator == &uid_lt)
|
|
+ audit_log_format(ab, "%s<(contains hex)%s", key, value);
|
|
+ else
|
|
+ audit_log_format(ab, "%s=(contains hex)%s", key, value);
|
|
+ } else {
|
|
+ if (rule_operator == &uid_gt)
|
|
+ audit_log_format(ab, "%s>", key);
|
|
+ else if (rule_operator == &uid_lt)
|
|
+ audit_log_format(ab, "%s<", key);
|
|
+ else
|
|
+ audit_log_format(ab, "%s=", key);
|
|
+ }
|
|
audit_log_format(ab, " ");
|
|
}
|
|
static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
|
|
diff --git a/integrity.h b/integrity.h
|
|
index 24520b4..c13e61d 100644
|
|
--- a/integrity.h
|
|
+++ b/integrity.h
|
|
@@ -16,6 +16,8 @@
|
|
#include <crypto/sha.h>
|
|
#include <linux/key.h>
|
|
|
|
+#include "kcompat.h"
|
|
+
|
|
/* iint action cache flags */
|
|
#define IMA_MEASURE 0x00000001
|
|
#define IMA_MEASURED 0x00000002
|
|
@@ -91,7 +93,7 @@ struct ima_digest_data {
|
|
struct signature_v2_hdr {
|
|
uint8_t type; /* xattr type */
|
|
uint8_t version; /* signature format version */
|
|
- uint8_t hash_algo; /* Digest algorithm [enum hash_algo] */
|
|
+ uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */
|
|
uint32_t keyid; /* IMA key identifier - not X509/PGP specific */
|
|
uint16_t sig_size; /* signature size */
|
|
uint8_t sig[0]; /* signature payload */
|
|
@@ -131,8 +133,8 @@ int __init integrity_read_file(const char *path, char **data);
|
|
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
|
const char *digest, int digestlen);
|
|
|
|
-int __init integrity_init_keyring(const unsigned int id);
|
|
-int __init integrity_load_x509(const unsigned int id, const char *path);
|
|
+int integrity_init_keyring(const unsigned int id);
|
|
+int integrity_load_x509(const unsigned int id, const char *path);
|
|
#else
|
|
|
|
static inline int integrity_digsig_verify(const unsigned int id,
|
|
diff --git a/integrity_audit.c b/integrity_audit.c
|
|
index 90987d1..ba5e532 100644
|
|
--- a/integrity_audit.c
|
|
+++ b/integrity_audit.c
|
|
@@ -10,6 +10,7 @@
|
|
* Audit calls for the integrity subsystem
|
|
*/
|
|
|
|
+#include "kcompat.h"
|
|
#include <linux/fs.h>
|
|
#include <linux/gfp.h>
|
|
#include <linux/audit.h>
|
|
@@ -45,21 +46,17 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
|
|
from_kuid(&init_user_ns, audit_get_loginuid(current)),
|
|
audit_get_sessionid(current));
|
|
audit_log_task_context(ab);
|
|
- audit_log_format(ab, " op=");
|
|
- audit_log_string(ab, op);
|
|
- audit_log_format(ab, " cause=");
|
|
- audit_log_string(ab, cause);
|
|
- audit_log_format(ab, " comm=");
|
|
- audit_log_untrustedstring(ab, get_task_comm(name, current));
|
|
+ audit_log_format(ab, " op=\"%s\"", op);
|
|
+ audit_log_format(ab, " cause=\"%s\"", cause);
|
|
+ audit_log_format(ab, " comm=%s", get_task_comm(name, current));
|
|
if (fname) {
|
|
- audit_log_format(ab, " name=");
|
|
- audit_log_untrustedstring(ab, fname);
|
|
+ audit_log_format(ab, " name=%s", fname);
|
|
}
|
|
if (inode) {
|
|
- audit_log_format(ab, " dev=");
|
|
- audit_log_untrustedstring(ab, inode->i_sb->s_id);
|
|
+ audit_log_format(ab, " dev=%s", inode->i_sb->s_id);
|
|
audit_log_format(ab, " ino=%lu", inode->i_ino);
|
|
}
|
|
audit_log_format(ab, " res=%d", !result);
|
|
audit_log_end(ab);
|
|
}
|
|
+EXPORT_SYMBOL_GPL(integrity_audit_msg);
|
|
diff --git a/kcompat.h b/kcompat.h
|
|
new file mode 100644
|
|
index 0000000..936b76c
|
|
--- /dev/null
|
|
+++ b/kcompat.h
|
|
@@ -0,0 +1,34 @@
|
|
+#ifndef _KCOMPAT_H_
|
|
+#define _KCOMPAT_H_
|
|
+
|
|
+#ifndef LINUX_VERSION_CODE
|
|
+#include <linux/version.h>
|
|
+#else
|
|
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
|
|
+#endif
|
|
+
|
|
+#if ( LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0) )
|
|
+
|
|
+/* kcompat definitions */
|
|
+#define CONFIG_TCG_TPM_MODULE 1
|
|
+
|
|
+#define CONFIG_IMA 1
|
|
+#define CONFIG_IMA_APPRAISE_SIGNED_INIT 1
|
|
+#define CONFIG_IMA_APPRAISE 1
|
|
+#define CONFIG_IMA_DEFAULT_HASH "sha256"
|
|
+#define CONFIG_IMA_MEASURE_PCR_IDX 10
|
|
+#define CONFIG_IMA_DEFAULT_TEMPLATE "ima-sig"
|
|
+#define CONFIG_INTEGRITY 1
|
|
+#define CONFIG_INTEGRITY_AUDIT 1
|
|
+#define CONFIG_INTEGRITY_ASYMMETRIC_KEYS 1
|
|
+#define CONFIG_INTEGRITY_SIGNATURE 1
|
|
+#define CONFIG_CRYPTO_RSA 1
|
|
+
|
|
+#define __GFP_RECLAIM __GFP_WAIT
|
|
+
|
|
+#define inode_lock(_node) mutex_lock(&_node->i_mutex)
|
|
+#define inode_unlock(_node) mutex_unlock(&_node->i_mutex)
|
|
+
|
|
+
|
|
+#endif
|
|
+#endif
|
|
--
|
|
1.8.3.1
|
|
|