ima_main.c 6.6 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;
57
	unsigned char *pathname = NULL, *pathbuf = NULL;
M
Mimi Zohar 已提交
58

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

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

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

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

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

79 80 81 82 83 84 85 86 87 88 89 90
	if (!send_tomtou && !send_writers)
		return;

	/* We will allow 11 spaces for ' (deleted)' to be appended */
	pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
	if (pathbuf) {
		pathname = d_path(&file->f_path, pathbuf, PATH_MAX + 11);
		if (IS_ERR(pathname))
			pathname = NULL;
		else if (strlen(pathname) > IMA_EVENT_NAME_LEN_MAX)
			pathname = NULL;
	}
91
	if (send_tomtou)
92 93 94
		ima_add_violation(inode,
				  !pathname ? dentry->d_name.name : pathname,
				  "invalid_pcr", "ToMToU");
95
	if (send_writers)
96 97 98 99
		ima_add_violation(inode,
				  !pathname ? dentry->d_name.name : pathname,
				  "invalid_pcr", "open_writers");
	kfree(pathbuf);
M
Mimi Zohar 已提交
100 101
}

102
static void ima_check_last_writer(struct integrity_iint_cache *iint,
E
Eric Paris 已提交
103 104 105
				  struct inode *inode,
				  struct file *file)
{
A
Al Viro 已提交
106
	fmode_t mode = file->f_mode;
E
Eric Paris 已提交
107

M
Mimi Zohar 已提交
108
	mutex_lock(&iint->mutex);
E
Eric Paris 已提交
109 110 111 112 113 114 115
	if (mode & FMODE_WRITE &&
	    atomic_read(&inode->i_writecount) == 1 &&
	    iint->version != inode->i_version)
		iint->flags &= ~IMA_MEASURED;
	mutex_unlock(&iint->mutex);
}

116 117 118 119
/**
 * ima_file_free - called on __fput()
 * @file: pointer to file structure being freed
 *
120
 * Flag files that changed, based on i_version
121 122 123 124
 */
void ima_file_free(struct file *file)
{
	struct inode *inode = file->f_dentry->d_inode;
125
	struct integrity_iint_cache *iint;
126

M
Mimi Zohar 已提交
127
	if (!iint_initialized || !S_ISREG(inode->i_mode))
128
		return;
129

130
	iint = integrity_iint_find(inode);
M
Mimi Zohar 已提交
131 132
	if (!iint)
		return;
133

M
Mimi Zohar 已提交
134
	ima_check_last_writer(iint, inode, file);
135 136 137 138 139 140
}

static int process_measurement(struct file *file, const unsigned char *filename,
			       int mask, int function)
{
	struct inode *inode = file->f_dentry->d_inode;
141
	struct integrity_iint_cache *iint;
142
	unsigned char *pathname = NULL, *pathbuf = NULL;
M
Mimi Zohar 已提交
143
	int rc = 0;
144 145 146

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

148
	rc = ima_must_measure(inode, mask, function);
E
Eric Paris 已提交
149 150 151
	if (rc != 0)
		return rc;
retry:
152
	iint = integrity_iint_find(inode);
E
Eric Paris 已提交
153
	if (!iint) {
154
		rc = integrity_inode_alloc(inode);
E
Eric Paris 已提交
155 156 157 158
		if (!rc || rc == -EEXIST)
			goto retry;
		return rc;
	}
159 160

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

162
	rc = iint->flags & IMA_MEASURED ? 1 : 0;
163 164 165 166
	if (rc != 0)
		goto out;

	rc = ima_collect_measurement(iint, file);
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
	if (rc != 0)
		goto out;

	if (function != BPRM_CHECK) {
		/* We will allow 11 spaces for ' (deleted)' to be appended */
		pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
		if (pathbuf) {
			pathname =
			    d_path(&file->f_path, pathbuf, PATH_MAX + 11);
			if (IS_ERR(pathname))
				pathname = NULL;
		}
	}
	ima_store_measurement(iint, file, !pathname ? filename : pathname);
	kfree(pathbuf);
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
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;

227 228 229
	rc = process_measurement(bprm->file,
				 (strcmp(bprm->filename, bprm->interp) == 0) ?
				 bprm->filename : bprm->interp,
230 231 232 233
				 MAY_EXEC, BPRM_CHECK);
	return 0;
}

M
Mimi Zohar 已提交
234 235 236 237 238 239 240 241 242 243
/**
 * 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.)
 */
244
int ima_file_check(struct file *file, int mask)
M
Mimi Zohar 已提交
245 246 247
{
	int rc;

248
	ima_rdwr_violation_check(file);
M
Mimi Zohar 已提交
249 250
	rc = process_measurement(file, file->f_dentry->d_name.name,
				 mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
251
				 FILE_CHECK);
M
Mimi Zohar 已提交
252 253
	return 0;
}
254
EXPORT_SYMBOL_GPL(ima_file_check);
M
Mimi Zohar 已提交
255

256 257 258 259 260
static int __init init_ima(void)
{
	int error;

	error = ima_init();
261 262
	if (!error)
		ima_initialized = 1;
263 264 265 266 267 268 269
	return error;
}

late_initcall(init_ima);	/* Start IMA after the TPM is available */

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