ima_main.c 5.8 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
#include <linux/ima.h>
26 27 28 29 30 31 32 33

#include "ima.h"

int ima_initialized;

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

M
Mimi Zohar 已提交
40
/*
41
 * ima_rdwr_violation_check
M
Mimi Zohar 已提交
42
 *
43
 * Only invalidate the PCR for measured files:
M
Mimi Zohar 已提交
44 45 46 47 48 49
 * 	- 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.
 *
 */
50
static void ima_rdwr_violation_check(struct file *file)
M
Mimi Zohar 已提交
51 52 53 54 55
{
	struct dentry *dentry = file->f_path.dentry;
	struct inode *inode = dentry->d_inode;
	fmode_t mode = file->f_mode;
	int rc;
56
	bool send_tomtou = false, send_writers = false;
M
Mimi Zohar 已提交
57

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

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

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

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

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

	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 已提交
84 85
}

86
static void ima_check_last_writer(struct integrity_iint_cache *iint,
E
Eric Paris 已提交
87 88 89
				  struct inode *inode,
				  struct file *file)
{
A
Al Viro 已提交
90
	fmode_t mode = file->f_mode;
E
Eric Paris 已提交
91

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

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

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

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

M
Mimi Zohar 已提交
118
	ima_check_last_writer(iint, inode, file);
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;
125
	struct integrity_iint_cache *iint;
M
Mimi Zohar 已提交
126
	int rc = 0;
127 128 129

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

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

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

145
	rc = iint->flags & IMA_MEASURED ? 1 : 0;
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 201
	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 已提交
202 203 204 205 206 207 208 209 210 211
/**
 * 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.)
 */
212
int ima_file_check(struct file *file, int mask)
M
Mimi Zohar 已提交
213 214 215
{
	int rc;

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

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

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

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

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

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