ima: support for kexec image and initramfs
authorMimi Zohar <zohar@linux.vnet.ibm.com>
Fri, 15 Jan 2016 01:59:14 +0000 (20:59 -0500)
committerMimi Zohar <zohar@linux.vnet.ibm.com>
Sun, 21 Feb 2016 14:06:16 +0000 (09:06 -0500)
Add IMA policy support for measuring/appraising the kexec image and
initramfs. Two new IMA policy identifiers KEXEC_KERNEL_CHECK and
KEXEC_INITRAMFS_CHECK are defined.

Example policy rules:
measure func=KEXEC_KERNEL_CHECK
appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig
measure func=KEXEC_INITRAMFS_CHECK
appraise func=KEXEC_INITRAMFS_CHECK appraise_type=imasig

Moving the enumeration to the vfs layer simplified the patches, allowing
the IMA changes, for the most part, to be separated from the other
changes.  Unfortunately, passing either a kernel_read_file_id or a
ima_hooks enumeration within IMA is messy.

Option 1: duplicate kernel_read_file enumeration in ima_hooks

enum kernel_read_file_id {
...
        READING_KEXEC_IMAGE,
        READING_KEXEC_INITRAMFS,
        READING_MAX_ID

enum ima_hooks {
...
KEXEC_KERNEL_CHECK
KEXEC_INITRAMFS_CHECK

Option 2: define ima_hooks as extension of kernel_read_file
eg: enum ima_hooks {
        FILE_CHECK = READING_MAX_ID,
        MMAP_CHECK,

In order to pass both kernel_read_file_id and ima_hooks values, we
would need to specify a struct containing a union.

struct caller_id {
        union {
                enum ima_hooks func_id;
                enum kernel_read_file_id read_id;
        };
};

Option 3: incorportate the ima_hooks enumeration into kernel_read_file_id,
perhaps changing the enumeration name.

For now, duplicate the new READING_KEXEC_IMAGE/INITRAMFS in the ima_hooks.

Changelog v4:
- replaced switch statement with a kernel_read_file_id to an ima_hooks
id mapping array - Dmitry
- renamed ima_hook tokens KEXEC_CHECK and INITRAMFS_CHECK to
KEXEC_KERNEL_CHECK and KEXEC_INITRAMFS_CHECK respectively - Dave Young

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Acked-by: Petko Manolov <petkan@mip-labs.com>
Acked-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
Cc: Dave Young <dyoung@redhat.com>
Documentation/ABI/testing/ima_policy
security/integrity/ima/ima.h
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c

index 0a378a88217a48a00b012435cba2ba2bdccd3fa6..bb0f9a135e21be07c5ef009d449fdb8656fb05d2 100644 (file)
@@ -27,6 +27,7 @@ Description:
 
                base:   func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
                                [FIRMWARE_CHECK]
+                               [KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
                        mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND]
                               [[^]MAY_EXEC]
                        fsmagic:= hex value
index a5d25921ee3c193887d64b50ec0f32e9923facb4..bd97e0d290de10e9253b8d1379f37d66d4af13e6 100644 (file)
@@ -147,6 +147,8 @@ enum ima_hooks {
        POST_SETATTR,
        MODULE_CHECK,
        FIRMWARE_CHECK,
+       KEXEC_KERNEL_CHECK,
+       KEXEC_INITRAMFS_CHECK,
        MAX_CHECK
 };
 
index 5da0b9c00072bdc4e10b4cf9c5f62235fdef9247..f76488162c1e663f1569e2160fd8ba4801f84c63 100644 (file)
@@ -339,6 +339,13 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id)
        return 0;
 }
 
+static int read_idmap[READING_MAX_ID] = {
+       [READING_FIRMWARE] = FIRMWARE_CHECK,
+       [READING_MODULE] = MODULE_CHECK,
+       [READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK,
+       [READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK,
+};
+
 /**
  * ima_post_read_file - in memory collect/appraise/audit measurement
  * @file: pointer to the file to be measured/appraised/audit
@@ -355,7 +362,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id)
 int ima_post_read_file(struct file *file, void *buf, loff_t size,
                       enum kernel_read_file_id read_id)
 {
-       enum ima_hooks func = FILE_CHECK;
+       enum ima_hooks func;
 
        if (!file && read_id == READING_FIRMWARE) {
                if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
@@ -373,11 +380,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
                return 0;
        }
 
-       if (read_id == READING_FIRMWARE)
-               func = FIRMWARE_CHECK;
-       else if (read_id == READING_MODULE)
-               func = MODULE_CHECK;
-
+       func = read_idmap[read_id] ?: FILE_CHECK;
        return process_measurement(file, buf, size, MAY_READ, func, 0);
 }
 
index 7571ce8841ffefdcaad0a67878c06e39566a9d79..646134cdf3e81d691d0d9616eeb0761baf92cd1a 100644 (file)
@@ -612,6 +612,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
                                entry->func = MMAP_CHECK;
                        else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
                                entry->func = BPRM_CHECK;
+                       else if (strcmp(args[0].from, "KEXEC_KERNEL_CHECK") ==
+                                0)
+                               entry->func = KEXEC_KERNEL_CHECK;
+                       else if (strcmp(args[0].from, "KEXEC_INITRAMFS_CHECK")
+                                == 0)
+                               entry->func = KEXEC_INITRAMFS_CHECK;
                        else
                                result = -EINVAL;
                        if (!result)
@@ -855,7 +861,8 @@ static char *mask_tokens[] = {
 
 enum {
        func_file = 0, func_mmap, func_bprm,
-       func_module, func_firmware, func_post
+       func_module, func_firmware, func_post,
+       func_kexec_kernel, func_kexec_initramfs
 };
 
 static char *func_tokens[] = {
@@ -864,6 +871,8 @@ static char *func_tokens[] = {
        "BPRM_CHECK",
        "MODULE_CHECK",
        "FIRMWARE_CHECK",
+       "KEXEC_KERNEL_CHECK",
+       "KEXEC_INITRAMFS_CHECK",
        "POST_SETATTR"
 };
 
@@ -929,6 +938,12 @@ static void policy_func_show(struct seq_file *m, enum ima_hooks func)
        case POST_SETATTR:
                seq_printf(m, pt(Opt_func), ft(func_post));
                break;
+       case KEXEC_KERNEL_CHECK:
+               seq_printf(m, pt(Opt_func), ft(func_kexec_kernel));
+               break;
+       case KEXEC_INITRAMFS_CHECK:
+               seq_printf(m, pt(Opt_func), ft(func_kexec_initramfs));
+               break;
        default:
                snprintf(tbuf, sizeof(tbuf), "%d", func);
                seq_printf(m, pt(Opt_func), tbuf);