aboutsummaryrefslogtreecommitdiff
path: root/security/pfe/pfk_ext4.c
blob: d505bcb10dab3a7935b78daf44a7c2a073188e29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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
/*
 * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

/*
 * Per-File-Key (PFK) - EXT4
 *
 * This driver is used for working with EXT4 crypt extension
 *
 * The key information  is stored in node by EXT4 when file is first opened
 * and will be later accessed by Block Device Driver to actually load the key
 * to encryption hw.
 *
 * PFK exposes API's for loading and removing keys from encryption hw
 * and also API to determine whether 2 adjacent blocks can be agregated by
 * Block Layer in one request to encryption hw.
 *
 */


/* Uncomment the line below to enable debug messages */
/* #define DEBUG 1 */
#define pr_fmt(fmt)	"pfk_ext4 [%s]: " fmt, __func__

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/printk.h>

#include "fscrypt_ice.h"
#include "pfk_ext4.h"
//#include "ext4_ice.h"

static bool pfk_ext4_ready;

/*
 * Deinit function, should be invoked by upper PFK layer
 */
void pfk_ext4_deinit(void)
{
	pfk_ext4_ready = false;
}
EXPORT_SYMBOL(pfk_ext4_deinit);

/*
 * Init function, should be invoked by upper PFK layer
 */
int __init pfk_ext4_init(void)
{
	pfk_ext4_ready = true;
	pr_info("PFK EXT4 inited successfully\n");

	return 0;
}
EXPORT_SYMBOL(pfk_ext4_init);

/*
 * Driver is initialized and ready.
 *
 * Return: true if the driver is ready.
 */
static inline bool pfk_ext4_is_ready(void)
{
	return pfk_ext4_ready;
}

/*
 * Checks if inode belongs to ICE EXT4 PFE
 */
bool pfk_is_ext4_type(const struct inode *inode)
{
	if (!pfe_is_inode_filesystem_type(inode, "ext4"))
		return false;

	return fscrypt_should_be_processed_by_ice(inode);
}
EXPORT_SYMBOL(pfk_is_ext4_type);

/*
 * parse cipher from inode to enum
 * @inode: inode
 * @algo: pointer to store the output enum (can be null)
 *
 * return 0 in case of success, error otherwise (i.e not supported cipher)
 */
static int pfk_ext4_parse_cipher(const struct inode *inode,
	enum ice_cryto_algo_mode *algo)
{
	/*
	 * currently only AES XTS algo is supported
	 * in the future, table with supported ciphers might
	 * be introduced
	 */

	if (!inode)
		return -EINVAL;

	if (!fscrypt_is_aes_xts_cipher(inode)) {
		pr_err("ext4 alghoritm is not supported by pfk\n");
		return -EINVAL;
	}

	if (algo)
		*algo = ICE_CRYPTO_ALGO_MODE_AES_XTS;

	return 0;
}

int pfk_ext4_parse_inode(const struct bio *bio,
	const struct inode *inode,
	struct pfk_key_info *key_info,
	enum ice_cryto_algo_mode *algo,
	bool *is_pfe)
{
	int ret = 0;

	if (!is_pfe)
		return -EINVAL;

	/*
	 * only a few errors below can indicate that
	 * this function was not invoked within PFE context,
	 * otherwise we will consider it PFE
	 */
	*is_pfe = true;

	if (!pfk_ext4_is_ready())
		return -ENODEV;

	if (!inode)
		return -EINVAL;

	if (!key_info)
		return -EINVAL;

	key_info->key = fscrypt_get_ice_encryption_key(inode);
	if (!key_info->key) {
		pr_err("could not parse key from ext4\n");
		return -EINVAL;
	}

	key_info->key_size = fscrypt_get_ice_encryption_key_size(inode);
	if (!key_info->key_size) {
		pr_err("could not parse key size from ext4\n");
		return -EINVAL;
	}

	key_info->salt = fscrypt_get_ice_encryption_salt(inode);
	if (!key_info->salt) {
		pr_err("could not parse salt from ext4\n");
		return -EINVAL;
	}

	key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode);
	if (!key_info->salt_size) {
		pr_err("could not parse salt size from ext4\n");
		return -EINVAL;
	}

	ret = pfk_ext4_parse_cipher(inode, algo);
	if (ret != 0) {
		pr_err("not supported cipher\n");
		return ret;
	}

	return 0;
}
EXPORT_SYMBOL(pfk_ext4_parse_inode);

bool pfk_ext4_allow_merge_bio(const struct bio *bio1,
	const struct bio *bio2, const struct inode *inode1,
	const struct inode *inode2)
{
	/* if there is no ext4 pfk, don't disallow merging blocks */
	if (!pfk_ext4_is_ready())
		return true;

	if (!inode1 || !inode2)
		return false;

	return fscrypt_is_ice_encryption_info_equal(inode1, inode2);
}
EXPORT_SYMBOL(pfk_ext4_allow_merge_bio);