xref: /optee_os/core/mm/fobj.c (revision ee5462896afc0dea013d2c3e9f99ce39626b148e)
1*ee546289SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2*ee546289SJens Wiklander /*
3*ee546289SJens Wiklander  * Copyright (c) 2019, Linaro Limited
4*ee546289SJens Wiklander  */
5*ee546289SJens Wiklander 
6*ee546289SJens Wiklander #include <crypto/crypto.h>
7*ee546289SJens Wiklander #include <crypto/internal_aes-gcm.h>
8*ee546289SJens Wiklander #include <kernel/panic.h>
9*ee546289SJens Wiklander #include <mm/core_memprot.h>
10*ee546289SJens Wiklander #include <mm/core_mmu.h>
11*ee546289SJens Wiklander #include <mm/fobj.h>
12*ee546289SJens Wiklander #include <mm/tee_mm.h>
13*ee546289SJens Wiklander #include <stdlib.h>
14*ee546289SJens Wiklander #include <string.h>
15*ee546289SJens Wiklander #include <tee_api_types.h>
16*ee546289SJens Wiklander #include <types_ext.h>
17*ee546289SJens Wiklander #include <util.h>
18*ee546289SJens Wiklander 
19*ee546289SJens Wiklander #ifdef CFG_WITH_PAGER
20*ee546289SJens Wiklander 
21*ee546289SJens Wiklander #define RWP_AE_KEY_BITS		256
22*ee546289SJens Wiklander 
23*ee546289SJens Wiklander struct rwp_aes_gcm_iv {
24*ee546289SJens Wiklander 	uint32_t iv[3];
25*ee546289SJens Wiklander };
26*ee546289SJens Wiklander 
27*ee546289SJens Wiklander #define RWP_AES_GCM_TAG_LEN	16
28*ee546289SJens Wiklander 
29*ee546289SJens Wiklander struct rwp_state {
30*ee546289SJens Wiklander 	uint64_t iv;
31*ee546289SJens Wiklander 	uint8_t tag[RWP_AES_GCM_TAG_LEN];
32*ee546289SJens Wiklander };
33*ee546289SJens Wiklander 
34*ee546289SJens Wiklander struct fobj_rwp {
35*ee546289SJens Wiklander 	uint8_t *store;
36*ee546289SJens Wiklander 	struct rwp_state *state;
37*ee546289SJens Wiklander 	struct fobj fobj;
38*ee546289SJens Wiklander };
39*ee546289SJens Wiklander 
40*ee546289SJens Wiklander static struct fobj_ops ops_rw_paged;
41*ee546289SJens Wiklander 
42*ee546289SJens Wiklander static struct internal_aes_gcm_key rwp_ae_key;
43*ee546289SJens Wiklander 
44*ee546289SJens Wiklander void fobj_generate_authenc_key(void)
45*ee546289SJens Wiklander {
46*ee546289SJens Wiklander 	uint8_t key[RWP_AE_KEY_BITS / 8] = { 0 };
47*ee546289SJens Wiklander 
48*ee546289SJens Wiklander 	if (crypto_rng_read(key, sizeof(key)) != TEE_SUCCESS)
49*ee546289SJens Wiklander 		panic("failed to generate random");
50*ee546289SJens Wiklander 	if (internal_aes_gcm_expand_enc_key(key, sizeof(key), &rwp_ae_key))
51*ee546289SJens Wiklander 		panic("failed to expand key");
52*ee546289SJens Wiklander }
53*ee546289SJens Wiklander 
54*ee546289SJens Wiklander static void fobj_init(struct fobj *fobj, const struct fobj_ops *ops,
55*ee546289SJens Wiklander 		      unsigned int num_pages)
56*ee546289SJens Wiklander {
57*ee546289SJens Wiklander 	fobj->ops = ops;
58*ee546289SJens Wiklander 	fobj->num_pages = num_pages;
59*ee546289SJens Wiklander 	refcount_set(&fobj->refc, 1);
60*ee546289SJens Wiklander }
61*ee546289SJens Wiklander 
62*ee546289SJens Wiklander static void fobj_uninit(struct fobj *fobj)
63*ee546289SJens Wiklander {
64*ee546289SJens Wiklander 	assert(!refcount_val(&fobj->refc));
65*ee546289SJens Wiklander }
66*ee546289SJens Wiklander 
67*ee546289SJens Wiklander struct fobj *fobj_rw_paged_alloc(unsigned int num_pages)
68*ee546289SJens Wiklander {
69*ee546289SJens Wiklander 	tee_mm_entry_t *mm = NULL;
70*ee546289SJens Wiklander 	struct fobj_rwp *rwp = NULL;
71*ee546289SJens Wiklander 	size_t size = 0;
72*ee546289SJens Wiklander 
73*ee546289SJens Wiklander 	assert(num_pages);
74*ee546289SJens Wiklander 
75*ee546289SJens Wiklander 	rwp = calloc(1, sizeof(*rwp));
76*ee546289SJens Wiklander 	if (!rwp)
77*ee546289SJens Wiklander 		return NULL;
78*ee546289SJens Wiklander 
79*ee546289SJens Wiklander 	rwp->state = calloc(num_pages, sizeof(*rwp->state));
80*ee546289SJens Wiklander 	if (!rwp->state)
81*ee546289SJens Wiklander 		goto err;
82*ee546289SJens Wiklander 
83*ee546289SJens Wiklander 	if (MUL_OVERFLOW(num_pages, SMALL_PAGE_SIZE, &size))
84*ee546289SJens Wiklander 		goto err;
85*ee546289SJens Wiklander 	mm = tee_mm_alloc(&tee_mm_sec_ddr, size);
86*ee546289SJens Wiklander 	if (!mm)
87*ee546289SJens Wiklander 		goto err;
88*ee546289SJens Wiklander 	rwp->store = phys_to_virt(tee_mm_get_smem(mm), MEM_AREA_TA_RAM);
89*ee546289SJens Wiklander 	assert(rwp->store); /* to assist debugging if it would ever happen */
90*ee546289SJens Wiklander 	if (!rwp->store)
91*ee546289SJens Wiklander 		goto err;
92*ee546289SJens Wiklander 
93*ee546289SJens Wiklander 	fobj_init(&rwp->fobj, &ops_rw_paged, num_pages);
94*ee546289SJens Wiklander 
95*ee546289SJens Wiklander 	return &rwp->fobj;
96*ee546289SJens Wiklander 
97*ee546289SJens Wiklander err:
98*ee546289SJens Wiklander 	tee_mm_free(mm);
99*ee546289SJens Wiklander 	free(rwp->state);
100*ee546289SJens Wiklander 	free(rwp);
101*ee546289SJens Wiklander 
102*ee546289SJens Wiklander 	return NULL;
103*ee546289SJens Wiklander }
104*ee546289SJens Wiklander 
105*ee546289SJens Wiklander static struct fobj_rwp *to_rwp(struct fobj *fobj)
106*ee546289SJens Wiklander {
107*ee546289SJens Wiklander 	assert(fobj->ops == &ops_rw_paged);
108*ee546289SJens Wiklander 
109*ee546289SJens Wiklander 	return container_of(fobj, struct fobj_rwp, fobj);
110*ee546289SJens Wiklander }
111*ee546289SJens Wiklander 
112*ee546289SJens Wiklander static void rwp_free(struct fobj *fobj)
113*ee546289SJens Wiklander {
114*ee546289SJens Wiklander 	struct fobj_rwp *rwp = to_rwp(fobj);
115*ee546289SJens Wiklander 
116*ee546289SJens Wiklander 	fobj_uninit(fobj);
117*ee546289SJens Wiklander 	tee_mm_free(tee_mm_find(&tee_mm_sec_ddr, virt_to_phys(rwp->store)));
118*ee546289SJens Wiklander 	free(rwp->state);
119*ee546289SJens Wiklander 	free(rwp);
120*ee546289SJens Wiklander }
121*ee546289SJens Wiklander 
122*ee546289SJens Wiklander static TEE_Result rwp_load_page(struct fobj *fobj, unsigned int page_idx,
123*ee546289SJens Wiklander 				void *va)
124*ee546289SJens Wiklander {
125*ee546289SJens Wiklander 	struct fobj_rwp *rwp = to_rwp(fobj);
126*ee546289SJens Wiklander 	struct rwp_state *state = rwp->state + page_idx;
127*ee546289SJens Wiklander 	uint8_t *src = rwp->store + page_idx * SMALL_PAGE_SIZE;
128*ee546289SJens Wiklander 	struct rwp_aes_gcm_iv iv = {
129*ee546289SJens Wiklander 		.iv = { (vaddr_t)state, state->iv >> 32, state->iv }
130*ee546289SJens Wiklander 	};
131*ee546289SJens Wiklander 
132*ee546289SJens Wiklander 	assert(refcount_val(&fobj->refc));
133*ee546289SJens Wiklander 	assert(page_idx < fobj->num_pages);
134*ee546289SJens Wiklander 
135*ee546289SJens Wiklander 	if (!state->iv) {
136*ee546289SJens Wiklander 		/*
137*ee546289SJens Wiklander 		 * iv still zero which means that this is previously unused
138*ee546289SJens Wiklander 		 * page.
139*ee546289SJens Wiklander 		 */
140*ee546289SJens Wiklander 		memset(va, 0, SMALL_PAGE_SIZE);
141*ee546289SJens Wiklander 		return TEE_SUCCESS;
142*ee546289SJens Wiklander 	}
143*ee546289SJens Wiklander 
144*ee546289SJens Wiklander 	return internal_aes_gcm_dec(&rwp_ae_key, &iv, sizeof(iv),
145*ee546289SJens Wiklander 				    NULL, 0, src, SMALL_PAGE_SIZE, va,
146*ee546289SJens Wiklander 				    state->tag, sizeof(state->tag));
147*ee546289SJens Wiklander }
148*ee546289SJens Wiklander KEEP_PAGER(rwp_load_page);
149*ee546289SJens Wiklander 
150*ee546289SJens Wiklander static TEE_Result rwp_save_page(struct fobj *fobj, unsigned int page_idx,
151*ee546289SJens Wiklander 				const void *va)
152*ee546289SJens Wiklander {
153*ee546289SJens Wiklander 	struct fobj_rwp *rwp = to_rwp(fobj);
154*ee546289SJens Wiklander 	struct rwp_state *state = rwp->state + page_idx;
155*ee546289SJens Wiklander 	size_t tag_len = sizeof(state->tag);
156*ee546289SJens Wiklander 	uint8_t *dst = rwp->store + page_idx * SMALL_PAGE_SIZE;
157*ee546289SJens Wiklander 	struct rwp_aes_gcm_iv iv;
158*ee546289SJens Wiklander 
159*ee546289SJens Wiklander 	memset(&iv, 0, sizeof(iv));
160*ee546289SJens Wiklander 	assert(refcount_val(&fobj->refc));
161*ee546289SJens Wiklander 	assert(page_idx < fobj->num_pages);
162*ee546289SJens Wiklander 	assert(state->iv + 1 > state->iv);
163*ee546289SJens Wiklander 
164*ee546289SJens Wiklander 	state->iv++;
165*ee546289SJens Wiklander 	/*
166*ee546289SJens Wiklander 	 * IV is constructed as recommended in section "8.2.1 Deterministic
167*ee546289SJens Wiklander 	 * Construction" of "Recommendation for Block Cipher Modes of
168*ee546289SJens Wiklander 	 * Operation: Galois/Counter Mode (GCM) and GMAC",
169*ee546289SJens Wiklander 	 * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
170*ee546289SJens Wiklander 	 */
171*ee546289SJens Wiklander 
172*ee546289SJens Wiklander 	iv.iv[0] = (vaddr_t)state;
173*ee546289SJens Wiklander 	iv.iv[1] = state->iv >> 32;
174*ee546289SJens Wiklander 	iv.iv[2] = state->iv;
175*ee546289SJens Wiklander 
176*ee546289SJens Wiklander 	return internal_aes_gcm_enc(&rwp_ae_key, &iv, sizeof(iv),
177*ee546289SJens Wiklander 				    NULL, 0, va, SMALL_PAGE_SIZE, dst,
178*ee546289SJens Wiklander 				    state->tag, &tag_len);
179*ee546289SJens Wiklander }
180*ee546289SJens Wiklander KEEP_PAGER(rwp_save_page);
181*ee546289SJens Wiklander 
182*ee546289SJens Wiklander static struct fobj_ops ops_rw_paged __rodata_unpaged = {
183*ee546289SJens Wiklander 	.free = rwp_free,
184*ee546289SJens Wiklander 	.load_page = rwp_load_page,
185*ee546289SJens Wiklander 	.save_page = rwp_save_page,
186*ee546289SJens Wiklander };
187*ee546289SJens Wiklander 
188*ee546289SJens Wiklander struct fobj_rop {
189*ee546289SJens Wiklander 	uint8_t *hashes;
190*ee546289SJens Wiklander 	uint8_t *store;
191*ee546289SJens Wiklander 	struct fobj fobj;
192*ee546289SJens Wiklander };
193*ee546289SJens Wiklander 
194*ee546289SJens Wiklander static struct fobj_ops ops_ro_paged;
195*ee546289SJens Wiklander 
196*ee546289SJens Wiklander struct fobj *fobj_ro_paged_alloc(unsigned int num_pages, void *hashes,
197*ee546289SJens Wiklander 				 void *store)
198*ee546289SJens Wiklander {
199*ee546289SJens Wiklander 	struct fobj_rop *rop = NULL;
200*ee546289SJens Wiklander 
201*ee546289SJens Wiklander 	assert(num_pages && hashes && store);
202*ee546289SJens Wiklander 
203*ee546289SJens Wiklander 	rop = calloc(1, sizeof(*rop));
204*ee546289SJens Wiklander 	if (!rop)
205*ee546289SJens Wiklander 		return NULL;
206*ee546289SJens Wiklander 
207*ee546289SJens Wiklander 	rop->hashes = hashes;
208*ee546289SJens Wiklander 	rop->store = store;
209*ee546289SJens Wiklander 	fobj_init(&rop->fobj, &ops_ro_paged, num_pages);
210*ee546289SJens Wiklander 
211*ee546289SJens Wiklander 	return &rop->fobj;
212*ee546289SJens Wiklander }
213*ee546289SJens Wiklander 
214*ee546289SJens Wiklander static struct fobj_rop *to_rop(struct fobj *fobj)
215*ee546289SJens Wiklander {
216*ee546289SJens Wiklander 	assert(fobj->ops == &ops_ro_paged);
217*ee546289SJens Wiklander 
218*ee546289SJens Wiklander 	return container_of(fobj, struct fobj_rop, fobj);
219*ee546289SJens Wiklander }
220*ee546289SJens Wiklander 
221*ee546289SJens Wiklander static void rop_free(struct fobj *fobj)
222*ee546289SJens Wiklander {
223*ee546289SJens Wiklander 	struct fobj_rop *rop = to_rop(fobj);
224*ee546289SJens Wiklander 
225*ee546289SJens Wiklander 	fobj_uninit(fobj);
226*ee546289SJens Wiklander 	tee_mm_free(tee_mm_find(&tee_mm_sec_ddr, virt_to_phys(rop->store)));
227*ee546289SJens Wiklander 	free(rop->hashes);
228*ee546289SJens Wiklander 	free(rop);
229*ee546289SJens Wiklander }
230*ee546289SJens Wiklander 
231*ee546289SJens Wiklander static TEE_Result rop_load_page(struct fobj *fobj, unsigned int page_idx,
232*ee546289SJens Wiklander 				void *va)
233*ee546289SJens Wiklander {
234*ee546289SJens Wiklander 	struct fobj_rop *rop = to_rop(fobj);
235*ee546289SJens Wiklander 	const uint8_t *hash = rop->hashes + page_idx * TEE_SHA256_HASH_SIZE;
236*ee546289SJens Wiklander 	const uint8_t *src = rop->store + page_idx * SMALL_PAGE_SIZE;
237*ee546289SJens Wiklander 
238*ee546289SJens Wiklander 	assert(refcount_val(&fobj->refc));
239*ee546289SJens Wiklander 	assert(page_idx < fobj->num_pages);
240*ee546289SJens Wiklander 	memcpy(va, src, SMALL_PAGE_SIZE);
241*ee546289SJens Wiklander 
242*ee546289SJens Wiklander 	return hash_sha256_check(hash, va, SMALL_PAGE_SIZE);
243*ee546289SJens Wiklander }
244*ee546289SJens Wiklander KEEP_PAGER(rop_load_page);
245*ee546289SJens Wiklander 
246*ee546289SJens Wiklander static TEE_Result rop_save_page(struct fobj *fobj __unused,
247*ee546289SJens Wiklander 				unsigned int page_idx __unused,
248*ee546289SJens Wiklander 				const void *va __unused)
249*ee546289SJens Wiklander {
250*ee546289SJens Wiklander 	return TEE_ERROR_GENERIC;
251*ee546289SJens Wiklander }
252*ee546289SJens Wiklander KEEP_PAGER(rop_save_page);
253*ee546289SJens Wiklander 
254*ee546289SJens Wiklander static struct fobj_ops ops_ro_paged __rodata_unpaged = {
255*ee546289SJens Wiklander 	.free = rop_free,
256*ee546289SJens Wiklander 	.load_page = rop_load_page,
257*ee546289SJens Wiklander 	.save_page = rop_save_page,
258*ee546289SJens Wiklander };
259*ee546289SJens Wiklander 
260*ee546289SJens Wiklander static struct fobj_ops ops_locked_paged;
261*ee546289SJens Wiklander 
262*ee546289SJens Wiklander struct fobj *fobj_locked_paged_alloc(unsigned int num_pages)
263*ee546289SJens Wiklander {
264*ee546289SJens Wiklander 	struct fobj *f = NULL;
265*ee546289SJens Wiklander 
266*ee546289SJens Wiklander 	assert(num_pages);
267*ee546289SJens Wiklander 
268*ee546289SJens Wiklander 	f = calloc(1, sizeof(*f));
269*ee546289SJens Wiklander 	if (!f)
270*ee546289SJens Wiklander 		return NULL;
271*ee546289SJens Wiklander 
272*ee546289SJens Wiklander 	fobj_init(f, &ops_locked_paged, num_pages);
273*ee546289SJens Wiklander 
274*ee546289SJens Wiklander 	return f;
275*ee546289SJens Wiklander }
276*ee546289SJens Wiklander 
277*ee546289SJens Wiklander static void lop_free(struct fobj *fobj)
278*ee546289SJens Wiklander {
279*ee546289SJens Wiklander 	assert(fobj->ops == &ops_locked_paged);
280*ee546289SJens Wiklander 	fobj_uninit(fobj);
281*ee546289SJens Wiklander 	free(fobj);
282*ee546289SJens Wiklander }
283*ee546289SJens Wiklander 
284*ee546289SJens Wiklander static TEE_Result lop_load_page(struct fobj *fobj __maybe_unused,
285*ee546289SJens Wiklander 				unsigned int page_idx __maybe_unused,
286*ee546289SJens Wiklander 				void *va)
287*ee546289SJens Wiklander {
288*ee546289SJens Wiklander 	assert(fobj->ops == &ops_locked_paged);
289*ee546289SJens Wiklander 	assert(refcount_val(&fobj->refc));
290*ee546289SJens Wiklander 	assert(page_idx < fobj->num_pages);
291*ee546289SJens Wiklander 
292*ee546289SJens Wiklander 	memset(va, 0, SMALL_PAGE_SIZE);
293*ee546289SJens Wiklander 
294*ee546289SJens Wiklander 	return TEE_SUCCESS;
295*ee546289SJens Wiklander }
296*ee546289SJens Wiklander KEEP_PAGER(lop_load_page);
297*ee546289SJens Wiklander 
298*ee546289SJens Wiklander static TEE_Result lop_save_page(struct fobj *fobj __unused,
299*ee546289SJens Wiklander 				unsigned int page_idx __unused,
300*ee546289SJens Wiklander 				const void *va __unused)
301*ee546289SJens Wiklander {
302*ee546289SJens Wiklander 	return TEE_ERROR_GENERIC;
303*ee546289SJens Wiklander }
304*ee546289SJens Wiklander KEEP_PAGER(lop_save_page);
305*ee546289SJens Wiklander 
306*ee546289SJens Wiklander static struct fobj_ops ops_locked_paged __rodata_unpaged = {
307*ee546289SJens Wiklander 	.free = lop_free,
308*ee546289SJens Wiklander 	.load_page = lop_load_page,
309*ee546289SJens Wiklander 	.save_page = lop_save_page,
310*ee546289SJens Wiklander };
311*ee546289SJens Wiklander #endif /*CFG_WITH_PAGER*/
312