xref: /openbmc/linux/security/integrity/ima/ima_fs.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2bab73937SMimi Zohar /*
3bab73937SMimi Zohar  * Copyright (C) 2005,2006,2007,2008 IBM Corporation
4bab73937SMimi Zohar  *
5bab73937SMimi Zohar  * Authors:
6bab73937SMimi Zohar  * Kylene Hall <kjhall@us.ibm.com>
7bab73937SMimi Zohar  * Reiner Sailer <sailer@us.ibm.com>
8bab73937SMimi Zohar  * Mimi Zohar <zohar@us.ibm.com>
9bab73937SMimi Zohar  *
10bab73937SMimi Zohar  * File: ima_fs.c
11bab73937SMimi Zohar  *	implemenents security file system for reporting
12bab73937SMimi Zohar  *	current measurement list and IMA statistics
13bab73937SMimi Zohar  */
14de636769SPetr Vorel 
15f850a7c0SEric Paris #include <linux/fcntl.h>
16b89999d0SScott Branden #include <linux/kernel_read_file.h>
175a0e3ad6STejun Heo #include <linux/slab.h>
18876979c9SPaul Gortmaker #include <linux/init.h>
19bab73937SMimi Zohar #include <linux/seq_file.h>
20bab73937SMimi Zohar #include <linux/rculist.h>
21bab73937SMimi Zohar #include <linux/rcupdate.h>
224af4662fSMimi Zohar #include <linux/parser.h>
237429b092SDmitry Kasatkin #include <linux/vmalloc.h>
24bab73937SMimi Zohar 
25bab73937SMimi Zohar #include "ima.h"
26bab73937SMimi Zohar 
2738d859f9SPetko Manolov static DEFINE_MUTEX(ima_write_mutex);
2838d859f9SPetko Manolov 
29d68a6fe9SMimi Zohar bool ima_canonical_fmt;
default_canonical_fmt_setup(char * str)30d68a6fe9SMimi Zohar static int __init default_canonical_fmt_setup(char *str)
31d68a6fe9SMimi Zohar {
32d68a6fe9SMimi Zohar #ifdef __BIG_ENDIAN
3339adb925SThomas Meyer 	ima_canonical_fmt = true;
34d68a6fe9SMimi Zohar #endif
35d68a6fe9SMimi Zohar 	return 1;
36d68a6fe9SMimi Zohar }
37d68a6fe9SMimi Zohar __setup("ima_canonical_fmt", default_canonical_fmt_setup);
38d68a6fe9SMimi Zohar 
394af4662fSMimi Zohar static int valid_policy = 1;
401e4c8dafSEric Biggers 
ima_show_htable_value(char __user * buf,size_t count,loff_t * ppos,atomic_long_t * val)41bab73937SMimi Zohar static ssize_t ima_show_htable_value(char __user *buf, size_t count,
42bab73937SMimi Zohar 				     loff_t *ppos, atomic_long_t *val)
43bab73937SMimi Zohar {
441e4c8dafSEric Biggers 	char tmpbuf[32];	/* greater than largest 'long' string value */
45bab73937SMimi Zohar 	ssize_t len;
46bab73937SMimi Zohar 
471e4c8dafSEric Biggers 	len = scnprintf(tmpbuf, sizeof(tmpbuf), "%li\n", atomic_long_read(val));
48bab73937SMimi Zohar 	return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
49bab73937SMimi Zohar }
50bab73937SMimi Zohar 
ima_show_htable_violations(struct file * filp,char __user * buf,size_t count,loff_t * ppos)51bab73937SMimi Zohar static ssize_t ima_show_htable_violations(struct file *filp,
52bab73937SMimi Zohar 					  char __user *buf,
53bab73937SMimi Zohar 					  size_t count, loff_t *ppos)
54bab73937SMimi Zohar {
55bab73937SMimi Zohar 	return ima_show_htable_value(buf, count, ppos, &ima_htable.violations);
56bab73937SMimi Zohar }
57bab73937SMimi Zohar 
58828c0950SAlexey Dobriyan static const struct file_operations ima_htable_violations_ops = {
59cdcd90f9SArnd Bergmann 	.read = ima_show_htable_violations,
60cdcd90f9SArnd Bergmann 	.llseek = generic_file_llseek,
61bab73937SMimi Zohar };
62bab73937SMimi Zohar 
ima_show_measurements_count(struct file * filp,char __user * buf,size_t count,loff_t * ppos)63bab73937SMimi Zohar static ssize_t ima_show_measurements_count(struct file *filp,
64bab73937SMimi Zohar 					   char __user *buf,
65bab73937SMimi Zohar 					   size_t count, loff_t *ppos)
66bab73937SMimi Zohar {
67bab73937SMimi Zohar 	return ima_show_htable_value(buf, count, ppos, &ima_htable.len);
68bab73937SMimi Zohar 
69bab73937SMimi Zohar }
70bab73937SMimi Zohar 
71828c0950SAlexey Dobriyan static const struct file_operations ima_measurements_count_ops = {
72cdcd90f9SArnd Bergmann 	.read = ima_show_measurements_count,
73cdcd90f9SArnd Bergmann 	.llseek = generic_file_llseek,
74bab73937SMimi Zohar };
75bab73937SMimi Zohar 
76bab73937SMimi Zohar /* returns pointer to hlist_node */
ima_measurements_start(struct seq_file * m,loff_t * pos)77bab73937SMimi Zohar static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
78bab73937SMimi Zohar {
79bab73937SMimi Zohar 	loff_t l = *pos;
80bab73937SMimi Zohar 	struct ima_queue_entry *qe;
81bab73937SMimi Zohar 
82bab73937SMimi Zohar 	/* we need a lock since pos could point beyond last element */
83bab73937SMimi Zohar 	rcu_read_lock();
84bab73937SMimi Zohar 	list_for_each_entry_rcu(qe, &ima_measurements, later) {
85bab73937SMimi Zohar 		if (!l--) {
86bab73937SMimi Zohar 			rcu_read_unlock();
87bab73937SMimi Zohar 			return qe;
88bab73937SMimi Zohar 		}
89bab73937SMimi Zohar 	}
90bab73937SMimi Zohar 	rcu_read_unlock();
91bab73937SMimi Zohar 	return NULL;
92bab73937SMimi Zohar }
93bab73937SMimi Zohar 
ima_measurements_next(struct seq_file * m,void * v,loff_t * pos)94bab73937SMimi Zohar static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
95bab73937SMimi Zohar {
96bab73937SMimi Zohar 	struct ima_queue_entry *qe = v;
97bab73937SMimi Zohar 
98bab73937SMimi Zohar 	/* lock protects when reading beyond last element
99bab73937SMimi Zohar 	 * against concurrent list-extension
100bab73937SMimi Zohar 	 */
101bab73937SMimi Zohar 	rcu_read_lock();
102089bc8e9SDmitry Kasatkin 	qe = list_entry_rcu(qe->later.next, struct ima_queue_entry, later);
103bab73937SMimi Zohar 	rcu_read_unlock();
104bab73937SMimi Zohar 	(*pos)++;
105bab73937SMimi Zohar 
106bab73937SMimi Zohar 	return (&qe->later == &ima_measurements) ? NULL : qe;
107bab73937SMimi Zohar }
108bab73937SMimi Zohar 
ima_measurements_stop(struct seq_file * m,void * v)109bab73937SMimi Zohar static void ima_measurements_stop(struct seq_file *m, void *v)
110bab73937SMimi Zohar {
111bab73937SMimi Zohar }
112bab73937SMimi Zohar 
ima_putc(struct seq_file * m,void * data,int datalen)1133ce1217dSRoberto Sassu void ima_putc(struct seq_file *m, void *data, int datalen)
114bab73937SMimi Zohar {
115bab73937SMimi Zohar 	while (datalen--)
116bab73937SMimi Zohar 		seq_putc(m, *(char *)data++);
117bab73937SMimi Zohar }
118bab73937SMimi Zohar 
119bab73937SMimi Zohar /* print format:
120bab73937SMimi Zohar  *       32bit-le=pcr#
121bab73937SMimi Zohar  *       char[20]=template digest
122bab73937SMimi Zohar  *       32bit-le=template name size
123bab73937SMimi Zohar  *       char[n]=template name
124a71dc65dSRoberto Sassu  *       [eventdata length]
125bab73937SMimi Zohar  *       eventdata[n]=template specific data
126bab73937SMimi Zohar  */
ima_measurements_show(struct seq_file * m,void * v)1277b8589ccSMimi Zohar int ima_measurements_show(struct seq_file *m, void *v)
128bab73937SMimi Zohar {
129bab73937SMimi Zohar 	/* the list never shrinks, so we don't need a lock here */
130bab73937SMimi Zohar 	struct ima_queue_entry *qe = v;
131bab73937SMimi Zohar 	struct ima_template_entry *e;
1327dbdb420SRoberto Sassu 	char *template_name;
133d68a6fe9SMimi Zohar 	u32 pcr, namelen, template_data_len; /* temporary fields */
1343e8e5503SRoberto Sassu 	bool is_ima_template = false;
135a71dc65dSRoberto Sassu 	int i;
136bab73937SMimi Zohar 
137bab73937SMimi Zohar 	/* get entry */
138bab73937SMimi Zohar 	e = qe->entry;
139bab73937SMimi Zohar 	if (e == NULL)
140bab73937SMimi Zohar 		return -1;
141bab73937SMimi Zohar 
1427dbdb420SRoberto Sassu 	template_name = (e->template_desc->name[0] != '\0') ?
1437dbdb420SRoberto Sassu 	    e->template_desc->name : e->template_desc->fmt;
1447dbdb420SRoberto Sassu 
145bab73937SMimi Zohar 	/*
146bab73937SMimi Zohar 	 * 1st: PCRIndex
1475f6f027bSEric Richter 	 * PCR used defaults to the same (config option) in
1485f6f027bSEric Richter 	 * little-endian format, unless set in policy
149bab73937SMimi Zohar 	 */
1506b26285fSRoberto Sassu 	pcr = !ima_canonical_fmt ? e->pcr : (__force u32)cpu_to_le32(e->pcr);
151d68a6fe9SMimi Zohar 	ima_putc(m, &pcr, sizeof(e->pcr));
152bab73937SMimi Zohar 
153bab73937SMimi Zohar 	/* 2nd: template digest */
154aa724fe1SRoberto Sassu 	ima_putc(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE);
155bab73937SMimi Zohar 
156bab73937SMimi Zohar 	/* 3rd: template name size */
157d68a6fe9SMimi Zohar 	namelen = !ima_canonical_fmt ? strlen(template_name) :
1586b26285fSRoberto Sassu 		(__force u32)cpu_to_le32(strlen(template_name));
1592bb930abSDmitry Kasatkin 	ima_putc(m, &namelen, sizeof(namelen));
160bab73937SMimi Zohar 
161bab73937SMimi Zohar 	/* 4th:  template name */
162d68a6fe9SMimi Zohar 	ima_putc(m, template_name, strlen(template_name));
163bab73937SMimi Zohar 
164a71dc65dSRoberto Sassu 	/* 5th:  template length (except for 'ima' template) */
1657dbdb420SRoberto Sassu 	if (strcmp(template_name, IMA_TEMPLATE_IMA_NAME) == 0)
1663e8e5503SRoberto Sassu 		is_ima_template = true;
1673e8e5503SRoberto Sassu 
168d68a6fe9SMimi Zohar 	if (!is_ima_template) {
169d68a6fe9SMimi Zohar 		template_data_len = !ima_canonical_fmt ? e->template_data_len :
1706b26285fSRoberto Sassu 			(__force u32)cpu_to_le32(e->template_data_len);
171d68a6fe9SMimi Zohar 		ima_putc(m, &template_data_len, sizeof(e->template_data_len));
172d68a6fe9SMimi Zohar 	}
173a71dc65dSRoberto Sassu 
174a71dc65dSRoberto Sassu 	/* 6th:  template specific data */
175a71dc65dSRoberto Sassu 	for (i = 0; i < e->template_desc->num_fields; i++) {
1763e8e5503SRoberto Sassu 		enum ima_show_type show = IMA_SHOW_BINARY;
177b2724d58SEric Biggers 		const struct ima_template_field *field =
178b2724d58SEric Biggers 			e->template_desc->fields[i];
1793e8e5503SRoberto Sassu 
1803e8e5503SRoberto Sassu 		if (is_ima_template && strcmp(field->field_id, "d") == 0)
1813e8e5503SRoberto Sassu 			show = IMA_SHOW_BINARY_NO_FIELD_LEN;
182c019e307SRoberto Sassu 		if (is_ima_template && strcmp(field->field_id, "n") == 0)
183c019e307SRoberto Sassu 			show = IMA_SHOW_BINARY_OLD_STRING_FMT;
1843e8e5503SRoberto Sassu 		field->field_show(m, show, &e->template_data[i]);
185a71dc65dSRoberto Sassu 	}
186bab73937SMimi Zohar 	return 0;
187bab73937SMimi Zohar }
188bab73937SMimi Zohar 
18988e9d34cSJames Morris static const struct seq_operations ima_measurments_seqops = {
190bab73937SMimi Zohar 	.start = ima_measurements_start,
191bab73937SMimi Zohar 	.next = ima_measurements_next,
192bab73937SMimi Zohar 	.stop = ima_measurements_stop,
193bab73937SMimi Zohar 	.show = ima_measurements_show
194bab73937SMimi Zohar };
195bab73937SMimi Zohar 
ima_measurements_open(struct inode * inode,struct file * file)196bab73937SMimi Zohar static int ima_measurements_open(struct inode *inode, struct file *file)
197bab73937SMimi Zohar {
198bab73937SMimi Zohar 	return seq_open(file, &ima_measurments_seqops);
199bab73937SMimi Zohar }
200bab73937SMimi Zohar 
201828c0950SAlexey Dobriyan static const struct file_operations ima_measurements_ops = {
202bab73937SMimi Zohar 	.open = ima_measurements_open,
203bab73937SMimi Zohar 	.read = seq_read,
204bab73937SMimi Zohar 	.llseek = seq_lseek,
205bab73937SMimi Zohar 	.release = seq_release,
206bab73937SMimi Zohar };
207bab73937SMimi Zohar 
ima_print_digest(struct seq_file * m,u8 * digest,u32 size)20845b26133SMimi Zohar void ima_print_digest(struct seq_file *m, u8 *digest, u32 size)
209bab73937SMimi Zohar {
21045b26133SMimi Zohar 	u32 i;
211bab73937SMimi Zohar 
212140d8022SMimi Zohar 	for (i = 0; i < size; i++)
213bab73937SMimi Zohar 		seq_printf(m, "%02x", *(digest + i));
214bab73937SMimi Zohar }
215bab73937SMimi Zohar 
216bab73937SMimi Zohar /* print in ascii */
ima_ascii_measurements_show(struct seq_file * m,void * v)217bab73937SMimi Zohar static int ima_ascii_measurements_show(struct seq_file *m, void *v)
218bab73937SMimi Zohar {
219bab73937SMimi Zohar 	/* the list never shrinks, so we don't need a lock here */
220bab73937SMimi Zohar 	struct ima_queue_entry *qe = v;
221bab73937SMimi Zohar 	struct ima_template_entry *e;
2227dbdb420SRoberto Sassu 	char *template_name;
223a71dc65dSRoberto Sassu 	int i;
224bab73937SMimi Zohar 
225bab73937SMimi Zohar 	/* get entry */
226bab73937SMimi Zohar 	e = qe->entry;
227bab73937SMimi Zohar 	if (e == NULL)
228bab73937SMimi Zohar 		return -1;
229bab73937SMimi Zohar 
2307dbdb420SRoberto Sassu 	template_name = (e->template_desc->name[0] != '\0') ?
2317dbdb420SRoberto Sassu 	    e->template_desc->name : e->template_desc->fmt;
2327dbdb420SRoberto Sassu 
233bab73937SMimi Zohar 	/* 1st: PCR used (config option) */
2345f6f027bSEric Richter 	seq_printf(m, "%2d ", e->pcr);
235bab73937SMimi Zohar 
236bab73937SMimi Zohar 	/* 2nd: SHA1 template hash */
237aa724fe1SRoberto Sassu 	ima_print_digest(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE);
238bab73937SMimi Zohar 
239bab73937SMimi Zohar 	/* 3th:  template name */
2407dbdb420SRoberto Sassu 	seq_printf(m, " %s", template_name);
241bab73937SMimi Zohar 
242bab73937SMimi Zohar 	/* 4th:  template specific data */
243a71dc65dSRoberto Sassu 	for (i = 0; i < e->template_desc->num_fields; i++) {
244a71dc65dSRoberto Sassu 		seq_puts(m, " ");
245a71dc65dSRoberto Sassu 		if (e->template_data[i].len == 0)
246a71dc65dSRoberto Sassu 			continue;
247a71dc65dSRoberto Sassu 
248a71dc65dSRoberto Sassu 		e->template_desc->fields[i]->field_show(m, IMA_SHOW_ASCII,
249a71dc65dSRoberto Sassu 							&e->template_data[i]);
250a71dc65dSRoberto Sassu 	}
251a71dc65dSRoberto Sassu 	seq_puts(m, "\n");
252bab73937SMimi Zohar 	return 0;
253bab73937SMimi Zohar }
254bab73937SMimi Zohar 
25588e9d34cSJames Morris static const struct seq_operations ima_ascii_measurements_seqops = {
256bab73937SMimi Zohar 	.start = ima_measurements_start,
257bab73937SMimi Zohar 	.next = ima_measurements_next,
258bab73937SMimi Zohar 	.stop = ima_measurements_stop,
259bab73937SMimi Zohar 	.show = ima_ascii_measurements_show
260bab73937SMimi Zohar };
261bab73937SMimi Zohar 
ima_ascii_measurements_open(struct inode * inode,struct file * file)262bab73937SMimi Zohar static int ima_ascii_measurements_open(struct inode *inode, struct file *file)
263bab73937SMimi Zohar {
264bab73937SMimi Zohar 	return seq_open(file, &ima_ascii_measurements_seqops);
265bab73937SMimi Zohar }
266bab73937SMimi Zohar 
267828c0950SAlexey Dobriyan static const struct file_operations ima_ascii_measurements_ops = {
268bab73937SMimi Zohar 	.open = ima_ascii_measurements_open,
269bab73937SMimi Zohar 	.read = seq_read,
270bab73937SMimi Zohar 	.llseek = seq_lseek,
271bab73937SMimi Zohar 	.release = seq_release,
272bab73937SMimi Zohar };
273bab73937SMimi Zohar 
ima_read_policy(char * path)2747429b092SDmitry Kasatkin static ssize_t ima_read_policy(char *path)
2757429b092SDmitry Kasatkin {
276c307459bSKees Cook 	void *data = NULL;
2777429b092SDmitry Kasatkin 	char *datap;
278f7a4f689SKees Cook 	size_t size;
2797429b092SDmitry Kasatkin 	int rc, pathlen = strlen(path);
2807429b092SDmitry Kasatkin 
2817429b092SDmitry Kasatkin 	char *p;
2827429b092SDmitry Kasatkin 
2837429b092SDmitry Kasatkin 	/* remove \n */
2847429b092SDmitry Kasatkin 	datap = path;
2857429b092SDmitry Kasatkin 	strsep(&datap, "\n");
2867429b092SDmitry Kasatkin 
2870fa8e084SKees Cook 	rc = kernel_read_file_from_path(path, 0, &data, INT_MAX, NULL,
2880fa8e084SKees Cook 					READING_POLICY);
2897429b092SDmitry Kasatkin 	if (rc < 0) {
2907429b092SDmitry Kasatkin 		pr_err("Unable to open file: %s (%d)", path, rc);
2917429b092SDmitry Kasatkin 		return rc;
2927429b092SDmitry Kasatkin 	}
293f7a4f689SKees Cook 	size = rc;
294f7a4f689SKees Cook 	rc = 0;
2957429b092SDmitry Kasatkin 
2967429b092SDmitry Kasatkin 	datap = data;
2977429b092SDmitry Kasatkin 	while (size > 0 && (p = strsep(&datap, "\n"))) {
2987429b092SDmitry Kasatkin 		pr_debug("rule: %s\n", p);
2997429b092SDmitry Kasatkin 		rc = ima_parse_add_rule(p);
3007429b092SDmitry Kasatkin 		if (rc < 0)
3017429b092SDmitry Kasatkin 			break;
3027429b092SDmitry Kasatkin 		size -= rc;
3037429b092SDmitry Kasatkin 	}
3047429b092SDmitry Kasatkin 
3057429b092SDmitry Kasatkin 	vfree(data);
3067429b092SDmitry Kasatkin 	if (rc < 0)
3077429b092SDmitry Kasatkin 		return rc;
3087429b092SDmitry Kasatkin 	else if (size)
3097429b092SDmitry Kasatkin 		return -EINVAL;
3107429b092SDmitry Kasatkin 	else
3117429b092SDmitry Kasatkin 		return pathlen;
3127429b092SDmitry Kasatkin }
3137429b092SDmitry Kasatkin 
ima_write_policy(struct file * file,const char __user * buf,size_t datalen,loff_t * ppos)3144af4662fSMimi Zohar static ssize_t ima_write_policy(struct file *file, const char __user *buf,
3154af4662fSMimi Zohar 				size_t datalen, loff_t *ppos)
3164af4662fSMimi Zohar {
3176427e6c7SPetko Manolov 	char *data;
3186ccd0456SEric Paris 	ssize_t result;
3194af4662fSMimi Zohar 
3204af4662fSMimi Zohar 	if (datalen >= PAGE_SIZE)
3216ccd0456SEric Paris 		datalen = PAGE_SIZE - 1;
3226ccd0456SEric Paris 
3234af4662fSMimi Zohar 	/* No partial writes. */
3246ccd0456SEric Paris 	result = -EINVAL;
3256ccd0456SEric Paris 	if (*ppos != 0)
3266ccd0456SEric Paris 		goto out;
3276ccd0456SEric Paris 
328b4e28030SGeliang Tang 	data = memdup_user_nul(buf, datalen);
329b4e28030SGeliang Tang 	if (IS_ERR(data)) {
330b4e28030SGeliang Tang 		result = PTR_ERR(data);
3316ccd0456SEric Paris 		goto out;
332b4e28030SGeliang Tang 	}
3336ccd0456SEric Paris 
3346427e6c7SPetko Manolov 	result = mutex_lock_interruptible(&ima_write_mutex);
3356427e6c7SPetko Manolov 	if (result < 0)
3366427e6c7SPetko Manolov 		goto out_free;
3377429b092SDmitry Kasatkin 
33819f8a847SMimi Zohar 	if (data[0] == '/') {
3397429b092SDmitry Kasatkin 		result = ima_read_policy(data);
34019f8a847SMimi Zohar 	} else if (ima_appraise & IMA_APPRAISE_POLICY) {
341de636769SPetr Vorel 		pr_err("signed policy file (specified as an absolute pathname) required\n");
34219f8a847SMimi Zohar 		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
34319f8a847SMimi Zohar 				    "policy_update", "signed policy required",
34419f8a847SMimi Zohar 				    1, 0);
34519f8a847SMimi Zohar 		result = -EACCES;
34619f8a847SMimi Zohar 	} else {
3476ccd0456SEric Paris 		result = ima_parse_add_rule(data);
34819f8a847SMimi Zohar 	}
3496427e6c7SPetko Manolov 	mutex_unlock(&ima_write_mutex);
3506427e6c7SPetko Manolov out_free:
3516427e6c7SPetko Manolov 	kfree(data);
3526ccd0456SEric Paris out:
3536ccd0456SEric Paris 	if (result < 0)
3546ccd0456SEric Paris 		valid_policy = 0;
35538d859f9SPetko Manolov 
3566ccd0456SEric Paris 	return result;
3574af4662fSMimi Zohar }
3584af4662fSMimi Zohar 
359bab73937SMimi Zohar static struct dentry *ima_dir;
3600c343af8SMatthew Garrett static struct dentry *ima_symlink;
361bab73937SMimi Zohar static struct dentry *binary_runtime_measurements;
362bab73937SMimi Zohar static struct dentry *ascii_runtime_measurements;
363bab73937SMimi Zohar static struct dentry *runtime_measurements_count;
364bab73937SMimi Zohar static struct dentry *violations;
3654af4662fSMimi Zohar static struct dentry *ima_policy;
3664af4662fSMimi Zohar 
3670716abbbSDmitry Kasatkin enum ima_fs_flags {
3680716abbbSDmitry Kasatkin 	IMA_FS_BUSY,
3690716abbbSDmitry Kasatkin };
3700716abbbSDmitry Kasatkin 
3710716abbbSDmitry Kasatkin static unsigned long ima_fs_flags;
3720716abbbSDmitry Kasatkin 
37380eae209SPetko Manolov #ifdef	CONFIG_IMA_READ_POLICY
37480eae209SPetko Manolov static const struct seq_operations ima_policy_seqops = {
37580eae209SPetko Manolov 		.start = ima_policy_start,
37680eae209SPetko Manolov 		.next = ima_policy_next,
37780eae209SPetko Manolov 		.stop = ima_policy_stop,
37880eae209SPetko Manolov 		.show = ima_policy_show,
37980eae209SPetko Manolov };
38080eae209SPetko Manolov #endif
38180eae209SPetko Manolov 
382f4bd857bSMimi Zohar /*
383f4bd857bSMimi Zohar  * ima_open_policy: sequentialize access to the policy file
384f4bd857bSMimi Zohar  */
ima_open_policy(struct inode * inode,struct file * filp)385b97e1452SJames Morris static int ima_open_policy(struct inode *inode, struct file *filp)
386f4bd857bSMimi Zohar {
38780eae209SPetko Manolov 	if (!(filp->f_flags & O_WRONLY)) {
38880eae209SPetko Manolov #ifndef	CONFIG_IMA_READ_POLICY
389f850a7c0SEric Paris 		return -EACCES;
39080eae209SPetko Manolov #else
39180eae209SPetko Manolov 		if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
39280eae209SPetko Manolov 			return -EACCES;
39380eae209SPetko Manolov 		if (!capable(CAP_SYS_ADMIN))
39480eae209SPetko Manolov 			return -EPERM;
39580eae209SPetko Manolov 		return seq_open(filp, &ima_policy_seqops);
39680eae209SPetko Manolov #endif
39780eae209SPetko Manolov 	}
3980716abbbSDmitry Kasatkin 	if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
399f4bd857bSMimi Zohar 		return -EBUSY;
4000716abbbSDmitry Kasatkin 	return 0;
401f4bd857bSMimi Zohar }
402f4bd857bSMimi Zohar 
4034af4662fSMimi Zohar /*
4044af4662fSMimi Zohar  * ima_release_policy - start using the new measure policy rules.
4054af4662fSMimi Zohar  *
4064af4662fSMimi Zohar  * Initially, ima_measure points to the default policy rules, now
407f4bd857bSMimi Zohar  * point to the new policy rules, and remove the securityfs policy file,
408f4bd857bSMimi Zohar  * assuming a valid policy.
4094af4662fSMimi Zohar  */
ima_release_policy(struct inode * inode,struct file * file)4104af4662fSMimi Zohar static int ima_release_policy(struct inode *inode, struct file *file)
4114af4662fSMimi Zohar {
4120716abbbSDmitry Kasatkin 	const char *cause = valid_policy ? "completed" : "failed";
4130716abbbSDmitry Kasatkin 
41480eae209SPetko Manolov 	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
4159a11a189SEric Richter 		return seq_release(inode, file);
41680eae209SPetko Manolov 
4170112721dSSasha Levin 	if (valid_policy && ima_check_policy() < 0) {
4180112721dSSasha Levin 		cause = "failed";
4190112721dSSasha Levin 		valid_policy = 0;
4200112721dSSasha Levin 	}
4210112721dSSasha Levin 
422de636769SPetr Vorel 	pr_info("policy update %s\n", cause);
4230716abbbSDmitry Kasatkin 	integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
4240716abbbSDmitry Kasatkin 			    "policy_update", cause, !valid_policy, 0);
4250716abbbSDmitry Kasatkin 
4264af4662fSMimi Zohar 	if (!valid_policy) {
4274af4662fSMimi Zohar 		ima_delete_rules();
428f4bd857bSMimi Zohar 		valid_policy = 1;
4290716abbbSDmitry Kasatkin 		clear_bit(IMA_FS_BUSY, &ima_fs_flags);
4304af4662fSMimi Zohar 		return 0;
4314af4662fSMimi Zohar 	}
43280eae209SPetko Manolov 
4334af4662fSMimi Zohar 	ima_update_policy();
4342068626dSMimi Zohar #if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY)
4354af4662fSMimi Zohar 	securityfs_remove(ima_policy);
4364af4662fSMimi Zohar 	ima_policy = NULL;
4372068626dSMimi Zohar #elif defined(CONFIG_IMA_WRITE_POLICY)
43838d859f9SPetko Manolov 	clear_bit(IMA_FS_BUSY, &ima_fs_flags);
439ffb122deSPetr Vorel #elif defined(CONFIG_IMA_READ_POLICY)
440ffb122deSPetr Vorel 	inode->i_mode &= ~S_IWUSR;
44138d859f9SPetko Manolov #endif
4424af4662fSMimi Zohar 	return 0;
4434af4662fSMimi Zohar }
4444af4662fSMimi Zohar 
445828c0950SAlexey Dobriyan static const struct file_operations ima_measure_policy_ops = {
446f4bd857bSMimi Zohar 	.open = ima_open_policy,
4474af4662fSMimi Zohar 	.write = ima_write_policy,
44880eae209SPetko Manolov 	.read = seq_read,
449cdcd90f9SArnd Bergmann 	.release = ima_release_policy,
450cdcd90f9SArnd Bergmann 	.llseek = generic_file_llseek,
4514af4662fSMimi Zohar };
452bab73937SMimi Zohar 
ima_fs_init(void)453932995f0SEric Paris int __init ima_fs_init(void)
454bab73937SMimi Zohar {
455*e4e071baSStefan Berger 	int ret;
456*e4e071baSStefan Berger 
4570c343af8SMatthew Garrett 	ima_dir = securityfs_create_dir("ima", integrity_dir);
458bab73937SMimi Zohar 	if (IS_ERR(ima_dir))
459*e4e071baSStefan Berger 		return PTR_ERR(ima_dir);
460bab73937SMimi Zohar 
4610c343af8SMatthew Garrett 	ima_symlink = securityfs_create_symlink("ima", NULL, "integrity/ima",
4620c343af8SMatthew Garrett 						NULL);
463*e4e071baSStefan Berger 	if (IS_ERR(ima_symlink)) {
464*e4e071baSStefan Berger 		ret = PTR_ERR(ima_symlink);
4650c343af8SMatthew Garrett 		goto out;
466*e4e071baSStefan Berger 	}
4670c343af8SMatthew Garrett 
468bab73937SMimi Zohar 	binary_runtime_measurements =
469bab73937SMimi Zohar 	    securityfs_create_file("binary_runtime_measurements",
470bab73937SMimi Zohar 				   S_IRUSR | S_IRGRP, ima_dir, NULL,
471bab73937SMimi Zohar 				   &ima_measurements_ops);
472*e4e071baSStefan Berger 	if (IS_ERR(binary_runtime_measurements)) {
473*e4e071baSStefan Berger 		ret = PTR_ERR(binary_runtime_measurements);
474bab73937SMimi Zohar 		goto out;
475*e4e071baSStefan Berger 	}
476bab73937SMimi Zohar 
477bab73937SMimi Zohar 	ascii_runtime_measurements =
478bab73937SMimi Zohar 	    securityfs_create_file("ascii_runtime_measurements",
479bab73937SMimi Zohar 				   S_IRUSR | S_IRGRP, ima_dir, NULL,
480bab73937SMimi Zohar 				   &ima_ascii_measurements_ops);
481*e4e071baSStefan Berger 	if (IS_ERR(ascii_runtime_measurements)) {
482*e4e071baSStefan Berger 		ret = PTR_ERR(ascii_runtime_measurements);
483bab73937SMimi Zohar 		goto out;
484*e4e071baSStefan Berger 	}
485bab73937SMimi Zohar 
486bab73937SMimi Zohar 	runtime_measurements_count =
487bab73937SMimi Zohar 	    securityfs_create_file("runtime_measurements_count",
488bab73937SMimi Zohar 				   S_IRUSR | S_IRGRP, ima_dir, NULL,
489bab73937SMimi Zohar 				   &ima_measurements_count_ops);
490*e4e071baSStefan Berger 	if (IS_ERR(runtime_measurements_count)) {
491*e4e071baSStefan Berger 		ret = PTR_ERR(runtime_measurements_count);
492bab73937SMimi Zohar 		goto out;
493*e4e071baSStefan Berger 	}
494bab73937SMimi Zohar 
495bab73937SMimi Zohar 	violations =
496bab73937SMimi Zohar 	    securityfs_create_file("violations", S_IRUSR | S_IRGRP,
497bab73937SMimi Zohar 				   ima_dir, NULL, &ima_htable_violations_ops);
498*e4e071baSStefan Berger 	if (IS_ERR(violations)) {
499*e4e071baSStefan Berger 		ret = PTR_ERR(violations);
500bab73937SMimi Zohar 		goto out;
501*e4e071baSStefan Berger 	}
502bab73937SMimi Zohar 
50380eae209SPetko Manolov 	ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
5044af4662fSMimi Zohar 					    ima_dir, NULL,
5054af4662fSMimi Zohar 					    &ima_measure_policy_ops);
506*e4e071baSStefan Berger 	if (IS_ERR(ima_policy)) {
507*e4e071baSStefan Berger 		ret = PTR_ERR(ima_policy);
5084af4662fSMimi Zohar 		goto out;
509*e4e071baSStefan Berger 	}
510bab73937SMimi Zohar 
5114af4662fSMimi Zohar 	return 0;
512bab73937SMimi Zohar out:
513f7333b95SStefan Berger 	securityfs_remove(ima_policy);
5140ea4f8aeSDmitry Kasatkin 	securityfs_remove(violations);
515bab73937SMimi Zohar 	securityfs_remove(runtime_measurements_count);
516bab73937SMimi Zohar 	securityfs_remove(ascii_runtime_measurements);
517bab73937SMimi Zohar 	securityfs_remove(binary_runtime_measurements);
5180c343af8SMatthew Garrett 	securityfs_remove(ima_symlink);
519bab73937SMimi Zohar 	securityfs_remove(ima_dir);
520*e4e071baSStefan Berger 
521*e4e071baSStefan Berger 	return ret;
522bab73937SMimi Zohar }
523