166dbc325SMimi Zohar /*
266dbc325SMimi Zohar  * Copyright (C) 2010 IBM Corporation
366dbc325SMimi Zohar  *
466dbc325SMimi Zohar  * Authors:
566dbc325SMimi Zohar  * Mimi Zohar <zohar@us.ibm.com>
666dbc325SMimi Zohar  *
766dbc325SMimi Zohar  * This program is free software; you can redistribute it and/or modify
866dbc325SMimi Zohar  * it under the terms of the GNU General Public License as published by
966dbc325SMimi Zohar  * the Free Software Foundation, version 2 of the License.
1066dbc325SMimi Zohar  *
1166dbc325SMimi Zohar  * File: evm_secfs.c
1266dbc325SMimi Zohar  *	- Used to signal when key is on keyring
1366dbc325SMimi Zohar  *	- Get the key and enable EVM
1466dbc325SMimi Zohar  */
1566dbc325SMimi Zohar 
1620ee451fSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1720ee451fSJoe Perches 
1866dbc325SMimi Zohar #include <linux/uaccess.h>
1966dbc325SMimi Zohar #include <linux/module.h>
2066dbc325SMimi Zohar #include "evm.h"
2166dbc325SMimi Zohar 
2266dbc325SMimi Zohar static struct dentry *evm_init_tpm;
2366dbc325SMimi Zohar 
2466dbc325SMimi Zohar /**
2566dbc325SMimi Zohar  * evm_read_key - read() for <securityfs>/evm
2666dbc325SMimi Zohar  *
2766dbc325SMimi Zohar  * @filp: file pointer, not actually used
2866dbc325SMimi Zohar  * @buf: where to put the result
2966dbc325SMimi Zohar  * @count: maximum to send along
3066dbc325SMimi Zohar  * @ppos: where to start
3166dbc325SMimi Zohar  *
3266dbc325SMimi Zohar  * Returns number of bytes read or error code, as appropriate
3366dbc325SMimi Zohar  */
3466dbc325SMimi Zohar static ssize_t evm_read_key(struct file *filp, char __user *buf,
3566dbc325SMimi Zohar 			    size_t count, loff_t *ppos)
3666dbc325SMimi Zohar {
3766dbc325SMimi Zohar 	char temp[80];
3866dbc325SMimi Zohar 	ssize_t rc;
3966dbc325SMimi Zohar 
4066dbc325SMimi Zohar 	if (*ppos != 0)
4166dbc325SMimi Zohar 		return 0;
4266dbc325SMimi Zohar 
43f00d7975SMatthew Garrett 	sprintf(temp, "%d", (evm_initialized & ~EVM_SETUP));
4466dbc325SMimi Zohar 	rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
4566dbc325SMimi Zohar 
4666dbc325SMimi Zohar 	return rc;
4766dbc325SMimi Zohar }
4866dbc325SMimi Zohar 
4966dbc325SMimi Zohar /**
5066dbc325SMimi Zohar  * evm_write_key - write() for <securityfs>/evm
5166dbc325SMimi Zohar  * @file: file pointer, not actually used
5266dbc325SMimi Zohar  * @buf: where to get the data from
5366dbc325SMimi Zohar  * @count: bytes sent
5466dbc325SMimi Zohar  * @ppos: where to start
5566dbc325SMimi Zohar  *
5666dbc325SMimi Zohar  * Used to signal that key is on the kernel key ring.
5766dbc325SMimi Zohar  * - get the integrity hmac key from the kernel key ring
5866dbc325SMimi Zohar  * - create list of hmac protected extended attributes
5966dbc325SMimi Zohar  * Returns number of bytes written or error code, as appropriate
6066dbc325SMimi Zohar  */
6166dbc325SMimi Zohar static ssize_t evm_write_key(struct file *file, const char __user *buf,
6266dbc325SMimi Zohar 			     size_t count, loff_t *ppos)
6366dbc325SMimi Zohar {
64f00d7975SMatthew Garrett 	int i, ret;
6566dbc325SMimi Zohar 
66f00d7975SMatthew Garrett 	if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_SETUP))
6766dbc325SMimi Zohar 		return -EPERM;
6866dbc325SMimi Zohar 
69f00d7975SMatthew Garrett 	ret = kstrtoint_from_user(buf, count, 0, &i);
70f00d7975SMatthew Garrett 
71f00d7975SMatthew Garrett 	if (ret)
72f00d7975SMatthew Garrett 		return ret;
73f00d7975SMatthew Garrett 
74f00d7975SMatthew Garrett 	/* Reject invalid values */
75f00d7975SMatthew Garrett 	if (!i || (i & ~EVM_INIT_MASK) != 0)
7666dbc325SMimi Zohar 		return -EINVAL;
7766dbc325SMimi Zohar 
78f00d7975SMatthew Garrett 	if (i & EVM_INIT_HMAC) {
79f00d7975SMatthew Garrett 		ret = evm_init_key();
80f00d7975SMatthew Garrett 		if (ret != 0)
81f00d7975SMatthew Garrett 			return ret;
82f00d7975SMatthew Garrett 		/* Forbid further writes after the symmetric key is loaded */
83f00d7975SMatthew Garrett 		i |= EVM_SETUP;
84f00d7975SMatthew Garrett 	}
8566dbc325SMimi Zohar 
86f00d7975SMatthew Garrett 	evm_initialized |= i;
8776266763SDmitry Kasatkin 
8866dbc325SMimi Zohar 	return count;
8966dbc325SMimi Zohar }
9066dbc325SMimi Zohar 
9166dbc325SMimi Zohar static const struct file_operations evm_key_ops = {
9266dbc325SMimi Zohar 	.read		= evm_read_key,
9366dbc325SMimi Zohar 	.write		= evm_write_key,
9466dbc325SMimi Zohar };
9566dbc325SMimi Zohar 
9666dbc325SMimi Zohar int __init evm_init_secfs(void)
9766dbc325SMimi Zohar {
9866dbc325SMimi Zohar 	int error = 0;
9966dbc325SMimi Zohar 
10066dbc325SMimi Zohar 	evm_init_tpm = securityfs_create_file("evm", S_IRUSR | S_IRGRP,
10166dbc325SMimi Zohar 					      NULL, NULL, &evm_key_ops);
10266dbc325SMimi Zohar 	if (!evm_init_tpm || IS_ERR(evm_init_tpm))
10366dbc325SMimi Zohar 		error = -EFAULT;
10466dbc325SMimi Zohar 	return error;
10566dbc325SMimi Zohar }
106