ima_main.c 5.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright (C) 2005,2006,2007,2008 IBM Corporation
 *
 * Authors:
 * Reiner Sailer <sailer@watson.ibm.com>
 * Serge Hallyn <serue@us.ibm.com>
 * Kylene Hall <kylene@us.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_main.c
16
 *	implements the IMA hooks: ima_bprm_check, ima_file_mmap,
17
 *	and ima_file_check.
18 19 20 21 22 23
 */
#include <linux/module.h>
#include <linux/file.h>
#include <linux/binfmts.h>
#include <linux/mount.h>
#include <linux/mman.h>
24
#include <linux/slab.h>
25 26 27 28 29 30 31 32

#include "ima.h"

int ima_initialized;

char *ima_hash = "sha1";
static int __init hash_setup(char *str)
{
33 34
	if (strncmp(str, "md5", 3) == 0)
		ima_hash = "md5";
35 36 37 38
	return 1;
}
__setup("ima_hash=", hash_setup);

M
Mimi Zohar 已提交
39
/*
40
 * ima_rdwr_violation_check
M
Mimi Zohar 已提交
41
 *
42
 * Only invalidate the PCR for measured files:
M
Mimi Zohar 已提交
43 44 45 46 47 48
 * 	- Opening a file for write when already open for read,
 *	  results in a time of measure, time of use (ToMToU) error.
 *	- Opening a file for read when already open for write,
 * 	  could result in a file measurement error.
 *
 */
49
static void ima_rdwr_violation_check(struct file *file)
M
Mimi Zohar 已提交
50 51 52 53 54
{
	struct dentry *dentry = file->f_path.dentry;
	struct inode *inode = dentry->d_inode;
	fmode_t mode = file->f_mode;
	int rc;
55
	bool send_tomtou = false, send_writers = false;
M
Mimi Zohar 已提交
56

57
	if (!S_ISREG(inode->i_mode) || !ima_initialized)
M
Mimi Zohar 已提交
58
		return;
59

60
	mutex_lock(&inode->i_mutex);	/* file metadata: permissions, xattr */
61

M
Mimi Zohar 已提交
62
	if (mode & FMODE_WRITE) {
M
Mimi Zohar 已提交
63
		if (atomic_read(&inode->i_readcount) && IS_IMA(inode))
64
			send_tomtou = true;
M
Mimi Zohar 已提交
65 66
		goto out;
	}
67

68
	rc = ima_must_measure(inode, MAY_READ, FILE_CHECK);
E
Eric Paris 已提交
69 70 71
	if (rc < 0)
		goto out;

72 73
	if (atomic_read(&inode->i_writecount) > 0)
		send_writers = true;
M
Mimi Zohar 已提交
74
out:
75
	mutex_unlock(&inode->i_mutex);
76 77 78 79 80 81 82

	if (send_tomtou)
		ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
				  "ToMToU");
	if (send_writers)
		ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
				  "open_writers");
M
Mimi Zohar 已提交
83 84
}

E
Eric Paris 已提交
85 86 87 88 89 90
static void ima_check_last_writer(struct ima_iint_cache *iint,
				  struct inode *inode,
				  struct file *file)
{
	mode_t mode = file->f_mode;

M
Mimi Zohar 已提交
91
	mutex_lock(&iint->mutex);
E
Eric Paris 已提交
92 93 94 95 96 97 98
	if (mode & FMODE_WRITE &&
	    atomic_read(&inode->i_writecount) == 1 &&
	    iint->version != inode->i_version)
		iint->flags &= ~IMA_MEASURED;
	mutex_unlock(&iint->mutex);
}

99 100 101 102
/**
 * ima_file_free - called on __fput()
 * @file: pointer to file structure being freed
 *
103
 * Flag files that changed, based on i_version
104 105 106 107 108 109
 */
void ima_file_free(struct file *file)
{
	struct inode *inode = file->f_dentry->d_inode;
	struct ima_iint_cache *iint;

M
Mimi Zohar 已提交
110
	if (!iint_initialized || !S_ISREG(inode->i_mode))
111
		return;
112

113
	iint = ima_iint_find(inode);
M
Mimi Zohar 已提交
114 115
	if (!iint)
		return;
116

M
Mimi Zohar 已提交
117
	ima_check_last_writer(iint, inode, file);
118 119 120 121 122 123 124
}

static int process_measurement(struct file *file, const unsigned char *filename,
			       int mask, int function)
{
	struct inode *inode = file->f_dentry->d_inode;
	struct ima_iint_cache *iint;
M
Mimi Zohar 已提交
125
	int rc = 0;
126 127 128

	if (!ima_initialized || !S_ISREG(inode->i_mode))
		return 0;
E
Eric Paris 已提交
129

130
	rc = ima_must_measure(inode, mask, function);
E
Eric Paris 已提交
131 132 133
	if (rc != 0)
		return rc;
retry:
134
	iint = ima_iint_find(inode);
E
Eric Paris 已提交
135 136 137 138 139 140
	if (!iint) {
		rc = ima_inode_alloc(inode);
		if (!rc || rc == -EEXIST)
			goto retry;
		return rc;
	}
141 142

	mutex_lock(&iint->mutex);
E
Eric Paris 已提交
143

144
	rc = iint->flags & IMA_MEASURED ? 1 : 0;
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
	if (rc != 0)
		goto out;

	rc = ima_collect_measurement(iint, file);
	if (!rc)
		ima_store_measurement(iint, file, filename);
out:
	mutex_unlock(&iint->mutex);
	return rc;
}

/**
 * ima_file_mmap - based on policy, collect/store measurement.
 * @file: pointer to the file to be measured (May be NULL)
 * @prot: contains the protection that will be applied by the kernel.
 *
 * Measure files being mmapped executable based on the ima_must_measure()
 * policy decision.
 *
 * Return 0 on success, an error code on failure.
 * (Based on the results of appraise_measurement().)
 */
int ima_file_mmap(struct file *file, unsigned long prot)
{
	int rc;

	if (!file)
		return 0;
	if (prot & PROT_EXEC)
		rc = process_measurement(file, file->f_dentry->d_name.name,
					 MAY_EXEC, FILE_MMAP);
	return 0;
}

/**
 * ima_bprm_check - based on policy, collect/store measurement.
 * @bprm: contains the linux_binprm structure
 *
 * The OS protects against an executable file, already open for write,
 * from being executed in deny_write_access() and an executable file,
 * already open for execute, from being modified in get_write_access().
 * So we can be certain that what we verify and measure here is actually
 * what is being executed.
 *
 * Return 0 on success, an error code on failure.
 * (Based on the results of appraise_measurement().)
 */
int ima_bprm_check(struct linux_binprm *bprm)
{
	int rc;

	rc = process_measurement(bprm->file, bprm->filename,
				 MAY_EXEC, BPRM_CHECK);
	return 0;
}

M
Mimi Zohar 已提交
201 202 203 204 205 206 207 208 209 210
/**
 * ima_path_check - based on policy, collect/store measurement.
 * @file: pointer to the file to be measured
 * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE
 *
 * Measure files based on the ima_must_measure() policy decision.
 *
 * Always return 0 and audit dentry_open failures.
 * (Return code will be based upon measurement appraisal.)
 */
211
int ima_file_check(struct file *file, int mask)
M
Mimi Zohar 已提交
212 213 214
{
	int rc;

215
	ima_rdwr_violation_check(file);
M
Mimi Zohar 已提交
216 217
	rc = process_measurement(file, file->f_dentry->d_name.name,
				 mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
218
				 FILE_CHECK);
M
Mimi Zohar 已提交
219 220
	return 0;
}
221
EXPORT_SYMBOL_GPL(ima_file_check);
M
Mimi Zohar 已提交
222

223 224 225 226 227 228 229 230 231
static int __init init_ima(void)
{
	int error;

	error = ima_init();
	ima_initialized = 1;
	return error;
}

M
Mimi Zohar 已提交
232 233 234 235 236
static void __exit cleanup_ima(void)
{
	ima_cleanup();
}

237 238 239 240
late_initcall(init_ima);	/* Start IMA after the TPM is available */

MODULE_DESCRIPTION("Integrity Measurement Architecture");
MODULE_LICENSE("GPL");