xref: /aosp_15_r20/external/e2fsprogs/e2fsck/encrypted_files.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker  * encrypted_files.c --- save information about encrypted files
3*6a54128fSAndroid Build Coastguard Worker  *
4*6a54128fSAndroid Build Coastguard Worker  * Copyright 2019 Google LLC
5*6a54128fSAndroid Build Coastguard Worker  *
6*6a54128fSAndroid Build Coastguard Worker  * %Begin-Header%
7*6a54128fSAndroid Build Coastguard Worker  * This file may be redistributed under the terms of the GNU Public
8*6a54128fSAndroid Build Coastguard Worker  * License.
9*6a54128fSAndroid Build Coastguard Worker  * %End-Header%
10*6a54128fSAndroid Build Coastguard Worker  */
11*6a54128fSAndroid Build Coastguard Worker 
12*6a54128fSAndroid Build Coastguard Worker /*
13*6a54128fSAndroid Build Coastguard Worker  * e2fsck pass 1 (inode table scan) creates a map from inode number to
14*6a54128fSAndroid Build Coastguard Worker  * encryption policy for all encrypted inodes.  But it's optimized so that the
15*6a54128fSAndroid Build Coastguard Worker  * full xattrs aren't saved but rather only 32-bit "policy IDs", since usually
16*6a54128fSAndroid Build Coastguard Worker  * many inodes share the same encryption policy.  This requires also maintaining
17*6a54128fSAndroid Build Coastguard Worker  * a second map, from policy to policy ID.  See add_encrypted_file().
18*6a54128fSAndroid Build Coastguard Worker  *
19*6a54128fSAndroid Build Coastguard Worker  * We also use run-length encoding to save memory when many adjacent inodes
20*6a54128fSAndroid Build Coastguard Worker  * share the same encryption policy, which is often the case too.
21*6a54128fSAndroid Build Coastguard Worker  *
22*6a54128fSAndroid Build Coastguard Worker  * e2fsck pass 2 (directory structure check) uses the inode => policy ID map to
23*6a54128fSAndroid Build Coastguard Worker  * verify that all regular files, directories, and symlinks in encrypted
24*6a54128fSAndroid Build Coastguard Worker  * directories use the directory's encryption policy.
25*6a54128fSAndroid Build Coastguard Worker  */
26*6a54128fSAndroid Build Coastguard Worker 
27*6a54128fSAndroid Build Coastguard Worker #include "config.h"
28*6a54128fSAndroid Build Coastguard Worker 
29*6a54128fSAndroid Build Coastguard Worker #include "e2fsck.h"
30*6a54128fSAndroid Build Coastguard Worker #include "problem.h"
31*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/rbtree.h"
32*6a54128fSAndroid Build Coastguard Worker 
33*6a54128fSAndroid Build Coastguard Worker #define FSCRYPT_KEY_DESCRIPTOR_SIZE	8
34*6a54128fSAndroid Build Coastguard Worker #define FSCRYPT_KEY_IDENTIFIER_SIZE	16
35*6a54128fSAndroid Build Coastguard Worker #define FS_KEY_DERIVATION_NONCE_SIZE	16
36*6a54128fSAndroid Build Coastguard Worker 
37*6a54128fSAndroid Build Coastguard Worker struct fscrypt_context_v1 {
38*6a54128fSAndroid Build Coastguard Worker 	__u8 version;
39*6a54128fSAndroid Build Coastguard Worker 	__u8 contents_encryption_mode;
40*6a54128fSAndroid Build Coastguard Worker 	__u8 filenames_encryption_mode;
41*6a54128fSAndroid Build Coastguard Worker 	__u8 flags;
42*6a54128fSAndroid Build Coastguard Worker 	__u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
43*6a54128fSAndroid Build Coastguard Worker 	__u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
44*6a54128fSAndroid Build Coastguard Worker };
45*6a54128fSAndroid Build Coastguard Worker 
46*6a54128fSAndroid Build Coastguard Worker struct fscrypt_context_v2 {
47*6a54128fSAndroid Build Coastguard Worker 	__u8 version;
48*6a54128fSAndroid Build Coastguard Worker 	__u8 contents_encryption_mode;
49*6a54128fSAndroid Build Coastguard Worker 	__u8 filenames_encryption_mode;
50*6a54128fSAndroid Build Coastguard Worker 	__u8 flags;
51*6a54128fSAndroid Build Coastguard Worker 	__u8 __reserved[4];
52*6a54128fSAndroid Build Coastguard Worker 	__u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE];
53*6a54128fSAndroid Build Coastguard Worker 	__u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
54*6a54128fSAndroid Build Coastguard Worker };
55*6a54128fSAndroid Build Coastguard Worker 
56*6a54128fSAndroid Build Coastguard Worker /* On-disk format of encryption xattr */
57*6a54128fSAndroid Build Coastguard Worker union fscrypt_context {
58*6a54128fSAndroid Build Coastguard Worker 	__u8 version;
59*6a54128fSAndroid Build Coastguard Worker 	struct fscrypt_context_v1 v1;
60*6a54128fSAndroid Build Coastguard Worker 	struct fscrypt_context_v2 v2;
61*6a54128fSAndroid Build Coastguard Worker };
62*6a54128fSAndroid Build Coastguard Worker 
63*6a54128fSAndroid Build Coastguard Worker struct fscrypt_policy_v1 {
64*6a54128fSAndroid Build Coastguard Worker 	__u8 version;
65*6a54128fSAndroid Build Coastguard Worker 	__u8 contents_encryption_mode;
66*6a54128fSAndroid Build Coastguard Worker 	__u8 filenames_encryption_mode;
67*6a54128fSAndroid Build Coastguard Worker 	__u8 flags;
68*6a54128fSAndroid Build Coastguard Worker 	__u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
69*6a54128fSAndroid Build Coastguard Worker };
70*6a54128fSAndroid Build Coastguard Worker 
71*6a54128fSAndroid Build Coastguard Worker struct fscrypt_policy_v2 {
72*6a54128fSAndroid Build Coastguard Worker 	__u8 version;
73*6a54128fSAndroid Build Coastguard Worker 	__u8 contents_encryption_mode;
74*6a54128fSAndroid Build Coastguard Worker 	__u8 filenames_encryption_mode;
75*6a54128fSAndroid Build Coastguard Worker 	__u8 flags;
76*6a54128fSAndroid Build Coastguard Worker 	__u8 __reserved[4];
77*6a54128fSAndroid Build Coastguard Worker 	__u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE];
78*6a54128fSAndroid Build Coastguard Worker };
79*6a54128fSAndroid Build Coastguard Worker 
80*6a54128fSAndroid Build Coastguard Worker /* The encryption "policy" is the fscrypt_context excluding the nonce. */
81*6a54128fSAndroid Build Coastguard Worker union fscrypt_policy {
82*6a54128fSAndroid Build Coastguard Worker 	__u8 version;
83*6a54128fSAndroid Build Coastguard Worker 	struct fscrypt_policy_v1 v1;
84*6a54128fSAndroid Build Coastguard Worker 	struct fscrypt_policy_v2 v2;
85*6a54128fSAndroid Build Coastguard Worker };
86*6a54128fSAndroid Build Coastguard Worker 
87*6a54128fSAndroid Build Coastguard Worker /* A range of inodes which share the same encryption policy */
88*6a54128fSAndroid Build Coastguard Worker struct encrypted_file_range {
89*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t		first_ino;
90*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t		last_ino;
91*6a54128fSAndroid Build Coastguard Worker 	__u32			policy_id;
92*6a54128fSAndroid Build Coastguard Worker };
93*6a54128fSAndroid Build Coastguard Worker 
94*6a54128fSAndroid Build Coastguard Worker /* Information about the encrypted files which have been seen so far */
95*6a54128fSAndroid Build Coastguard Worker struct encrypted_file_info {
96*6a54128fSAndroid Build Coastguard Worker 	/*
97*6a54128fSAndroid Build Coastguard Worker 	 * Map from inode number to encryption policy ID, implemented as a
98*6a54128fSAndroid Build Coastguard Worker 	 * sorted array of inode ranges, each of which shares the same policy.
99*6a54128fSAndroid Build Coastguard Worker 	 * Inodes are added in order of increasing inode number.
100*6a54128fSAndroid Build Coastguard Worker 	 *
101*6a54128fSAndroid Build Coastguard Worker 	 * Freed after pass 2.
102*6a54128fSAndroid Build Coastguard Worker 	 */
103*6a54128fSAndroid Build Coastguard Worker 	struct encrypted_file_range	*file_ranges;
104*6a54128fSAndroid Build Coastguard Worker 	size_t				file_ranges_count;
105*6a54128fSAndroid Build Coastguard Worker 	size_t				file_ranges_capacity;
106*6a54128fSAndroid Build Coastguard Worker 
107*6a54128fSAndroid Build Coastguard Worker 	/*
108*6a54128fSAndroid Build Coastguard Worker 	 * Map from encryption policy to encryption policy ID, for the unique
109*6a54128fSAndroid Build Coastguard Worker 	 * encryption policies that have been seen so far.  next_policy_id is
110*6a54128fSAndroid Build Coastguard Worker 	 * the next available ID, starting at 0.
111*6a54128fSAndroid Build Coastguard Worker 	 *
112*6a54128fSAndroid Build Coastguard Worker 	 * Freed after pass 1.
113*6a54128fSAndroid Build Coastguard Worker 	 */
114*6a54128fSAndroid Build Coastguard Worker 	struct rb_root		policies;
115*6a54128fSAndroid Build Coastguard Worker 	__u32			next_policy_id;
116*6a54128fSAndroid Build Coastguard Worker };
117*6a54128fSAndroid Build Coastguard Worker 
118*6a54128fSAndroid Build Coastguard Worker /* Entry in encrypted_file_info::policies */
119*6a54128fSAndroid Build Coastguard Worker struct policy_map_entry {
120*6a54128fSAndroid Build Coastguard Worker 	union fscrypt_policy	policy;
121*6a54128fSAndroid Build Coastguard Worker 	__u32			policy_id;
122*6a54128fSAndroid Build Coastguard Worker 	struct rb_node		node;
123*6a54128fSAndroid Build Coastguard Worker };
124*6a54128fSAndroid Build Coastguard Worker 
cmp_fscrypt_policies(e2fsck_t ctx,const union fscrypt_policy * a,const union fscrypt_policy * b)125*6a54128fSAndroid Build Coastguard Worker static int cmp_fscrypt_policies(e2fsck_t ctx, const union fscrypt_policy *a,
126*6a54128fSAndroid Build Coastguard Worker 				const union fscrypt_policy *b)
127*6a54128fSAndroid Build Coastguard Worker {
128*6a54128fSAndroid Build Coastguard Worker 	if (a->version != b->version)
129*6a54128fSAndroid Build Coastguard Worker 		return (int)a->version - (int)b->version;
130*6a54128fSAndroid Build Coastguard Worker 
131*6a54128fSAndroid Build Coastguard Worker 	switch (a->version) {
132*6a54128fSAndroid Build Coastguard Worker 	case 1:
133*6a54128fSAndroid Build Coastguard Worker 		return memcmp(a, b, sizeof(a->v1));
134*6a54128fSAndroid Build Coastguard Worker 	case 2:
135*6a54128fSAndroid Build Coastguard Worker 		return memcmp(a, b, sizeof(a->v2));
136*6a54128fSAndroid Build Coastguard Worker 	}
137*6a54128fSAndroid Build Coastguard Worker 	fatal_error(ctx, "Unhandled encryption policy version");
138*6a54128fSAndroid Build Coastguard Worker 	return 0;
139*6a54128fSAndroid Build Coastguard Worker }
140*6a54128fSAndroid Build Coastguard Worker 
141*6a54128fSAndroid Build Coastguard Worker /* Read an inode's encryption xattr. */
read_encryption_xattr(e2fsck_t ctx,ext2_ino_t ino,void ** value,size_t * value_len)142*6a54128fSAndroid Build Coastguard Worker static errcode_t read_encryption_xattr(e2fsck_t ctx, ext2_ino_t ino,
143*6a54128fSAndroid Build Coastguard Worker 				       void **value, size_t *value_len)
144*6a54128fSAndroid Build Coastguard Worker {
145*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr_handle *h;
146*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval;
147*6a54128fSAndroid Build Coastguard Worker 
148*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_xattrs_open(ctx->fs, ino, &h);
149*6a54128fSAndroid Build Coastguard Worker 	if (retval)
150*6a54128fSAndroid Build Coastguard Worker 		return retval;
151*6a54128fSAndroid Build Coastguard Worker 
152*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_xattrs_read(h);
153*6a54128fSAndroid Build Coastguard Worker 	if (retval == 0)
154*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_xattr_get(h, "c", value, value_len);
155*6a54128fSAndroid Build Coastguard Worker 
156*6a54128fSAndroid Build Coastguard Worker 	ext2fs_xattrs_close(&h);
157*6a54128fSAndroid Build Coastguard Worker 	return retval;
158*6a54128fSAndroid Build Coastguard Worker }
159*6a54128fSAndroid Build Coastguard Worker 
160*6a54128fSAndroid Build Coastguard Worker /*
161*6a54128fSAndroid Build Coastguard Worker  * Convert an fscrypt_context to an fscrypt_policy.  Returns 0,
162*6a54128fSAndroid Build Coastguard Worker  * CORRUPT_ENCRYPTION_POLICY, or UNRECOGNIZED_ENCRYPTION_POLICY.
163*6a54128fSAndroid Build Coastguard Worker  */
fscrypt_context_to_policy(const void * xattr,size_t xattr_size,union fscrypt_policy * policy_u)164*6a54128fSAndroid Build Coastguard Worker static __u32 fscrypt_context_to_policy(const void *xattr, size_t xattr_size,
165*6a54128fSAndroid Build Coastguard Worker 				       union fscrypt_policy *policy_u)
166*6a54128fSAndroid Build Coastguard Worker {
167*6a54128fSAndroid Build Coastguard Worker 	const union fscrypt_context *ctx_u = xattr;
168*6a54128fSAndroid Build Coastguard Worker 
169*6a54128fSAndroid Build Coastguard Worker 	if (xattr_size < 1)
170*6a54128fSAndroid Build Coastguard Worker 		return CORRUPT_ENCRYPTION_POLICY;
171*6a54128fSAndroid Build Coastguard Worker 	switch (ctx_u->version) {
172*6a54128fSAndroid Build Coastguard Worker 	case 0:
173*6a54128fSAndroid Build Coastguard Worker 		return CORRUPT_ENCRYPTION_POLICY;
174*6a54128fSAndroid Build Coastguard Worker 	case 1: {
175*6a54128fSAndroid Build Coastguard Worker 		struct fscrypt_policy_v1 *policy = &policy_u->v1;
176*6a54128fSAndroid Build Coastguard Worker 		const struct fscrypt_context_v1 *ctx = &ctx_u->v1;
177*6a54128fSAndroid Build Coastguard Worker 
178*6a54128fSAndroid Build Coastguard Worker 		if (xattr_size != sizeof(*ctx))
179*6a54128fSAndroid Build Coastguard Worker 			return CORRUPT_ENCRYPTION_POLICY;
180*6a54128fSAndroid Build Coastguard Worker 		policy->version = ctx->version;
181*6a54128fSAndroid Build Coastguard Worker 		policy->contents_encryption_mode =
182*6a54128fSAndroid Build Coastguard Worker 			ctx->contents_encryption_mode;
183*6a54128fSAndroid Build Coastguard Worker 		policy->filenames_encryption_mode =
184*6a54128fSAndroid Build Coastguard Worker 			ctx->filenames_encryption_mode;
185*6a54128fSAndroid Build Coastguard Worker 		policy->flags = ctx->flags;
186*6a54128fSAndroid Build Coastguard Worker 		memcpy(policy->master_key_descriptor,
187*6a54128fSAndroid Build Coastguard Worker 		       ctx->master_key_descriptor,
188*6a54128fSAndroid Build Coastguard Worker 		       sizeof(policy->master_key_descriptor));
189*6a54128fSAndroid Build Coastguard Worker 		return 0;
190*6a54128fSAndroid Build Coastguard Worker 	}
191*6a54128fSAndroid Build Coastguard Worker 	case 2: {
192*6a54128fSAndroid Build Coastguard Worker 		struct fscrypt_policy_v2 *policy = &policy_u->v2;
193*6a54128fSAndroid Build Coastguard Worker 		const struct fscrypt_context_v2 *ctx = &ctx_u->v2;
194*6a54128fSAndroid Build Coastguard Worker 
195*6a54128fSAndroid Build Coastguard Worker 		if (xattr_size != sizeof(*ctx))
196*6a54128fSAndroid Build Coastguard Worker 			return CORRUPT_ENCRYPTION_POLICY;
197*6a54128fSAndroid Build Coastguard Worker 		policy->version = ctx->version;
198*6a54128fSAndroid Build Coastguard Worker 		policy->contents_encryption_mode =
199*6a54128fSAndroid Build Coastguard Worker 			ctx->contents_encryption_mode;
200*6a54128fSAndroid Build Coastguard Worker 		policy->filenames_encryption_mode =
201*6a54128fSAndroid Build Coastguard Worker 			ctx->filenames_encryption_mode;
202*6a54128fSAndroid Build Coastguard Worker 		policy->flags = ctx->flags;
203*6a54128fSAndroid Build Coastguard Worker 		memcpy(policy->__reserved, ctx->__reserved,
204*6a54128fSAndroid Build Coastguard Worker 		       sizeof(policy->__reserved));
205*6a54128fSAndroid Build Coastguard Worker 		memcpy(policy->master_key_identifier,
206*6a54128fSAndroid Build Coastguard Worker 		       ctx->master_key_identifier,
207*6a54128fSAndroid Build Coastguard Worker 		       sizeof(policy->master_key_identifier));
208*6a54128fSAndroid Build Coastguard Worker 		return 0;
209*6a54128fSAndroid Build Coastguard Worker 	}
210*6a54128fSAndroid Build Coastguard Worker 	}
211*6a54128fSAndroid Build Coastguard Worker 	return UNRECOGNIZED_ENCRYPTION_POLICY;
212*6a54128fSAndroid Build Coastguard Worker }
213*6a54128fSAndroid Build Coastguard Worker 
214*6a54128fSAndroid Build Coastguard Worker /*
215*6a54128fSAndroid Build Coastguard Worker  * Read an inode's encryption xattr and get/allocate its encryption policy ID,
216*6a54128fSAndroid Build Coastguard Worker  * or alternatively use one of the special IDs NO_ENCRYPTION_POLICY,
217*6a54128fSAndroid Build Coastguard Worker  * CORRUPT_ENCRYPTION_POLICY, or UNRECOGNIZED_ENCRYPTION_POLICY.
218*6a54128fSAndroid Build Coastguard Worker  *
219*6a54128fSAndroid Build Coastguard Worker  * Returns nonzero only if out of memory.
220*6a54128fSAndroid Build Coastguard Worker  */
get_encryption_policy_id(e2fsck_t ctx,ext2_ino_t ino,__u32 * policy_id_ret)221*6a54128fSAndroid Build Coastguard Worker static errcode_t get_encryption_policy_id(e2fsck_t ctx, ext2_ino_t ino,
222*6a54128fSAndroid Build Coastguard Worker 					  __u32 *policy_id_ret)
223*6a54128fSAndroid Build Coastguard Worker {
224*6a54128fSAndroid Build Coastguard Worker 	struct encrypted_file_info *info = ctx->encrypted_files;
225*6a54128fSAndroid Build Coastguard Worker 	struct rb_node **new = &info->policies.rb_node;
226*6a54128fSAndroid Build Coastguard Worker 	struct rb_node *parent = NULL;
227*6a54128fSAndroid Build Coastguard Worker 	void *xattr;
228*6a54128fSAndroid Build Coastguard Worker 	size_t xattr_size;
229*6a54128fSAndroid Build Coastguard Worker 	union fscrypt_policy policy;
230*6a54128fSAndroid Build Coastguard Worker 	__u32 policy_id;
231*6a54128fSAndroid Build Coastguard Worker 	struct policy_map_entry *entry;
232*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval;
233*6a54128fSAndroid Build Coastguard Worker 
234*6a54128fSAndroid Build Coastguard Worker 	retval = read_encryption_xattr(ctx, ino, &xattr, &xattr_size);
235*6a54128fSAndroid Build Coastguard Worker 	if (retval == EXT2_ET_NO_MEMORY)
236*6a54128fSAndroid Build Coastguard Worker 		return retval;
237*6a54128fSAndroid Build Coastguard Worker 	if (retval) {
238*6a54128fSAndroid Build Coastguard Worker 		*policy_id_ret = NO_ENCRYPTION_POLICY;
239*6a54128fSAndroid Build Coastguard Worker 		return 0;
240*6a54128fSAndroid Build Coastguard Worker 	}
241*6a54128fSAndroid Build Coastguard Worker 
242*6a54128fSAndroid Build Coastguard Worker 	/* Translate the xattr to an fscrypt_policy, if possible. */
243*6a54128fSAndroid Build Coastguard Worker 	policy_id = fscrypt_context_to_policy(xattr, xattr_size, &policy);
244*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&xattr);
245*6a54128fSAndroid Build Coastguard Worker 	if (policy_id != 0)
246*6a54128fSAndroid Build Coastguard Worker 		goto out;
247*6a54128fSAndroid Build Coastguard Worker 
248*6a54128fSAndroid Build Coastguard Worker 	/* Check if the policy was already seen. */
249*6a54128fSAndroid Build Coastguard Worker 	while (*new) {
250*6a54128fSAndroid Build Coastguard Worker 		int res;
251*6a54128fSAndroid Build Coastguard Worker 
252*6a54128fSAndroid Build Coastguard Worker 		parent = *new;
253*6a54128fSAndroid Build Coastguard Worker 		entry = ext2fs_rb_entry(parent, struct policy_map_entry, node);
254*6a54128fSAndroid Build Coastguard Worker 		res = cmp_fscrypt_policies(ctx, &policy, &entry->policy);
255*6a54128fSAndroid Build Coastguard Worker 		if (res < 0) {
256*6a54128fSAndroid Build Coastguard Worker 			new = &parent->rb_left;
257*6a54128fSAndroid Build Coastguard Worker 		} else if (res > 0) {
258*6a54128fSAndroid Build Coastguard Worker 			new = &parent->rb_right;
259*6a54128fSAndroid Build Coastguard Worker 		} else {
260*6a54128fSAndroid Build Coastguard Worker 			/* Policy already seen.  Use existing ID. */
261*6a54128fSAndroid Build Coastguard Worker 			policy_id = entry->policy_id;
262*6a54128fSAndroid Build Coastguard Worker 			goto out;
263*6a54128fSAndroid Build Coastguard Worker 		}
264*6a54128fSAndroid Build Coastguard Worker 	}
265*6a54128fSAndroid Build Coastguard Worker 
266*6a54128fSAndroid Build Coastguard Worker 	/* First time seeing this policy.  Allocate a new policy ID. */
267*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_get_mem(sizeof(*entry), &entry);
268*6a54128fSAndroid Build Coastguard Worker 	if (retval)
269*6a54128fSAndroid Build Coastguard Worker 		goto out;
270*6a54128fSAndroid Build Coastguard Worker 	policy_id = info->next_policy_id++;
271*6a54128fSAndroid Build Coastguard Worker 	entry->policy_id = policy_id;
272*6a54128fSAndroid Build Coastguard Worker 	entry->policy = policy;
273*6a54128fSAndroid Build Coastguard Worker 	ext2fs_rb_link_node(&entry->node, parent, new);
274*6a54128fSAndroid Build Coastguard Worker 	ext2fs_rb_insert_color(&entry->node, &info->policies);
275*6a54128fSAndroid Build Coastguard Worker out:
276*6a54128fSAndroid Build Coastguard Worker 	*policy_id_ret = policy_id;
277*6a54128fSAndroid Build Coastguard Worker 	return retval;
278*6a54128fSAndroid Build Coastguard Worker }
279*6a54128fSAndroid Build Coastguard Worker 
handle_nomem(e2fsck_t ctx,struct problem_context * pctx,size_t size_needed)280*6a54128fSAndroid Build Coastguard Worker static int handle_nomem(e2fsck_t ctx, struct problem_context *pctx,
281*6a54128fSAndroid Build Coastguard Worker 			size_t size_needed)
282*6a54128fSAndroid Build Coastguard Worker {
283*6a54128fSAndroid Build Coastguard Worker 	pctx->num = size_needed;
284*6a54128fSAndroid Build Coastguard Worker 	fix_problem(ctx, PR_1_ALLOCATE_ENCRYPTED_INODE_LIST, pctx);
285*6a54128fSAndroid Build Coastguard Worker 	/* Should never get here */
286*6a54128fSAndroid Build Coastguard Worker 	ctx->flags |= E2F_FLAG_ABORT;
287*6a54128fSAndroid Build Coastguard Worker 	return 0;
288*6a54128fSAndroid Build Coastguard Worker }
289*6a54128fSAndroid Build Coastguard Worker 
append_ino_and_policy_id(e2fsck_t ctx,struct problem_context * pctx,ext2_ino_t ino,__u32 policy_id)290*6a54128fSAndroid Build Coastguard Worker static int append_ino_and_policy_id(e2fsck_t ctx, struct problem_context *pctx,
291*6a54128fSAndroid Build Coastguard Worker 				    ext2_ino_t ino, __u32 policy_id)
292*6a54128fSAndroid Build Coastguard Worker {
293*6a54128fSAndroid Build Coastguard Worker 	struct encrypted_file_info *info = ctx->encrypted_files;
294*6a54128fSAndroid Build Coastguard Worker 	struct encrypted_file_range *range;
295*6a54128fSAndroid Build Coastguard Worker 
296*6a54128fSAndroid Build Coastguard Worker 	/* See if we can just extend the last range. */
297*6a54128fSAndroid Build Coastguard Worker 	if (info->file_ranges_count > 0) {
298*6a54128fSAndroid Build Coastguard Worker 		range = &info->file_ranges[info->file_ranges_count - 1];
299*6a54128fSAndroid Build Coastguard Worker 
300*6a54128fSAndroid Build Coastguard Worker 		if (ino <= range->last_ino) {
301*6a54128fSAndroid Build Coastguard Worker 			/* Should never get here */
302*6a54128fSAndroid Build Coastguard Worker 			fatal_error(ctx,
303*6a54128fSAndroid Build Coastguard Worker 				    "Encrypted inodes processed out of order");
304*6a54128fSAndroid Build Coastguard Worker 		}
305*6a54128fSAndroid Build Coastguard Worker 
306*6a54128fSAndroid Build Coastguard Worker 		if (ino == range->last_ino + 1 &&
307*6a54128fSAndroid Build Coastguard Worker 		    policy_id == range->policy_id) {
308*6a54128fSAndroid Build Coastguard Worker 			range->last_ino++;
309*6a54128fSAndroid Build Coastguard Worker 			return 0;
310*6a54128fSAndroid Build Coastguard Worker 		}
311*6a54128fSAndroid Build Coastguard Worker 	}
312*6a54128fSAndroid Build Coastguard Worker 	/* Nope, a new range is needed. */
313*6a54128fSAndroid Build Coastguard Worker 
314*6a54128fSAndroid Build Coastguard Worker 	if (info->file_ranges_count == info->file_ranges_capacity) {
315*6a54128fSAndroid Build Coastguard Worker 		/* Double the capacity by default. */
316*6a54128fSAndroid Build Coastguard Worker 		size_t new_capacity = info->file_ranges_capacity * 2;
317*6a54128fSAndroid Build Coastguard Worker 
318*6a54128fSAndroid Build Coastguard Worker 		/* ... but go from 0 to 128 right away. */
319*6a54128fSAndroid Build Coastguard Worker 		if (new_capacity < 128)
320*6a54128fSAndroid Build Coastguard Worker 			new_capacity = 128;
321*6a54128fSAndroid Build Coastguard Worker 
322*6a54128fSAndroid Build Coastguard Worker 		/* We won't need more than the filesystem's inode count. */
323*6a54128fSAndroid Build Coastguard Worker 		if (new_capacity > ctx->fs->super->s_inodes_count)
324*6a54128fSAndroid Build Coastguard Worker 			new_capacity = ctx->fs->super->s_inodes_count;
325*6a54128fSAndroid Build Coastguard Worker 
326*6a54128fSAndroid Build Coastguard Worker 		/* To be safe, ensure the capacity really increases. */
327*6a54128fSAndroid Build Coastguard Worker 		if (new_capacity < info->file_ranges_capacity + 1)
328*6a54128fSAndroid Build Coastguard Worker 			new_capacity = info->file_ranges_capacity + 1;
329*6a54128fSAndroid Build Coastguard Worker 
330*6a54128fSAndroid Build Coastguard Worker 		if (ext2fs_resize_mem(info->file_ranges_capacity *
331*6a54128fSAndroid Build Coastguard Worker 					sizeof(*range),
332*6a54128fSAndroid Build Coastguard Worker 				      new_capacity * sizeof(*range),
333*6a54128fSAndroid Build Coastguard Worker 				      &info->file_ranges) != 0)
334*6a54128fSAndroid Build Coastguard Worker 			return handle_nomem(ctx, pctx,
335*6a54128fSAndroid Build Coastguard Worker 					    new_capacity * sizeof(*range));
336*6a54128fSAndroid Build Coastguard Worker 
337*6a54128fSAndroid Build Coastguard Worker 		info->file_ranges_capacity = new_capacity;
338*6a54128fSAndroid Build Coastguard Worker 	}
339*6a54128fSAndroid Build Coastguard Worker 	range = &info->file_ranges[info->file_ranges_count++];
340*6a54128fSAndroid Build Coastguard Worker 	range->first_ino = ino;
341*6a54128fSAndroid Build Coastguard Worker 	range->last_ino = ino;
342*6a54128fSAndroid Build Coastguard Worker 	range->policy_id = policy_id;
343*6a54128fSAndroid Build Coastguard Worker 	return 0;
344*6a54128fSAndroid Build Coastguard Worker }
345*6a54128fSAndroid Build Coastguard Worker 
346*6a54128fSAndroid Build Coastguard Worker /*
347*6a54128fSAndroid Build Coastguard Worker  * Handle an inode that has EXT4_ENCRYPT_FL set during pass 1.  Normally this
348*6a54128fSAndroid Build Coastguard Worker  * just finds the unique ID that identifies the inode's encryption policy
349*6a54128fSAndroid Build Coastguard Worker  * (allocating a new ID if needed), and adds the inode number and its policy ID
350*6a54128fSAndroid Build Coastguard Worker  * to the encrypted_file_info so that it's available in pass 2.
351*6a54128fSAndroid Build Coastguard Worker  *
352*6a54128fSAndroid Build Coastguard Worker  * But this also handles:
353*6a54128fSAndroid Build Coastguard Worker  * - If the inode doesn't have an encryption xattr at all, offer to clear the
354*6a54128fSAndroid Build Coastguard Worker  *   encrypt flag.
355*6a54128fSAndroid Build Coastguard Worker  * - If the encryption xattr is clearly corrupt, tell the caller that the whole
356*6a54128fSAndroid Build Coastguard Worker  *   inode should be cleared.
357*6a54128fSAndroid Build Coastguard Worker  * - To be future-proof: if the encryption xattr has an unrecognized version
358*6a54128fSAndroid Build Coastguard Worker  *   number, it *might* be valid, so we don't consider it invalid.  But we can't
359*6a54128fSAndroid Build Coastguard Worker  *   do much with it, so give all such policies the same ID,
360*6a54128fSAndroid Build Coastguard Worker  *   UNRECOGNIZED_ENCRYPTION_POLICY.
361*6a54128fSAndroid Build Coastguard Worker  *
362*6a54128fSAndroid Build Coastguard Worker  * Returns -1 if the inode should be cleared, otherwise 0.
363*6a54128fSAndroid Build Coastguard Worker  */
add_encrypted_file(e2fsck_t ctx,struct problem_context * pctx)364*6a54128fSAndroid Build Coastguard Worker int add_encrypted_file(e2fsck_t ctx, struct problem_context *pctx)
365*6a54128fSAndroid Build Coastguard Worker {
366*6a54128fSAndroid Build Coastguard Worker 	struct encrypted_file_info *info = ctx->encrypted_files;
367*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t ino = pctx->ino;
368*6a54128fSAndroid Build Coastguard Worker 	__u32 policy_id;
369*6a54128fSAndroid Build Coastguard Worker 
370*6a54128fSAndroid Build Coastguard Worker 	/* Allocate the encrypted_file_info if needed. */
371*6a54128fSAndroid Build Coastguard Worker 	if (info == NULL) {
372*6a54128fSAndroid Build Coastguard Worker 		if (ext2fs_get_memzero(sizeof(*info), &info) != 0)
373*6a54128fSAndroid Build Coastguard Worker 			return handle_nomem(ctx, pctx, sizeof(*info));
374*6a54128fSAndroid Build Coastguard Worker 		ctx->encrypted_files = info;
375*6a54128fSAndroid Build Coastguard Worker 	}
376*6a54128fSAndroid Build Coastguard Worker 
377*6a54128fSAndroid Build Coastguard Worker 	/* Get a unique ID for this inode's encryption policy. */
378*6a54128fSAndroid Build Coastguard Worker 	if (get_encryption_policy_id(ctx, ino, &policy_id) != 0)
379*6a54128fSAndroid Build Coastguard Worker 		return handle_nomem(ctx, pctx, 0 /* unknown size */);
380*6a54128fSAndroid Build Coastguard Worker 	if (policy_id == NO_ENCRYPTION_POLICY) {
381*6a54128fSAndroid Build Coastguard Worker 		if (fix_problem(ctx, PR_1_MISSING_ENCRYPTION_XATTR, pctx)) {
382*6a54128fSAndroid Build Coastguard Worker 			pctx->inode->i_flags &= ~EXT4_ENCRYPT_FL;
383*6a54128fSAndroid Build Coastguard Worker 			e2fsck_write_inode(ctx, ino, pctx->inode, "pass1");
384*6a54128fSAndroid Build Coastguard Worker 		}
385*6a54128fSAndroid Build Coastguard Worker 		return 0;
386*6a54128fSAndroid Build Coastguard Worker 	} else if (policy_id == CORRUPT_ENCRYPTION_POLICY) {
387*6a54128fSAndroid Build Coastguard Worker 		if (fix_problem(ctx, PR_1_CORRUPT_ENCRYPTION_XATTR, pctx))
388*6a54128fSAndroid Build Coastguard Worker 			return -1;
389*6a54128fSAndroid Build Coastguard Worker 		return 0;
390*6a54128fSAndroid Build Coastguard Worker 	}
391*6a54128fSAndroid Build Coastguard Worker 
392*6a54128fSAndroid Build Coastguard Worker 	/* Store this ino => policy_id mapping in the encrypted_file_info. */
393*6a54128fSAndroid Build Coastguard Worker 	return append_ino_and_policy_id(ctx, pctx, ino, policy_id);
394*6a54128fSAndroid Build Coastguard Worker }
395*6a54128fSAndroid Build Coastguard Worker 
396*6a54128fSAndroid Build Coastguard Worker /*
397*6a54128fSAndroid Build Coastguard Worker  * Find the ID of an inode's encryption policy, using the information saved
398*6a54128fSAndroid Build Coastguard Worker  * earlier.
399*6a54128fSAndroid Build Coastguard Worker  *
400*6a54128fSAndroid Build Coastguard Worker  * If the inode is encrypted, returns the policy ID or
401*6a54128fSAndroid Build Coastguard Worker  * UNRECOGNIZED_ENCRYPTION_POLICY.  Else, returns NO_ENCRYPTION_POLICY.
402*6a54128fSAndroid Build Coastguard Worker  */
find_encryption_policy(e2fsck_t ctx,ext2_ino_t ino)403*6a54128fSAndroid Build Coastguard Worker __u32 find_encryption_policy(e2fsck_t ctx, ext2_ino_t ino)
404*6a54128fSAndroid Build Coastguard Worker {
405*6a54128fSAndroid Build Coastguard Worker 	const struct encrypted_file_info *info = ctx->encrypted_files;
406*6a54128fSAndroid Build Coastguard Worker 	size_t l, r;
407*6a54128fSAndroid Build Coastguard Worker 
408*6a54128fSAndroid Build Coastguard Worker 	if (info == NULL)
409*6a54128fSAndroid Build Coastguard Worker 		return NO_ENCRYPTION_POLICY;
410*6a54128fSAndroid Build Coastguard Worker 	l = 0;
411*6a54128fSAndroid Build Coastguard Worker 	r = info->file_ranges_count;
412*6a54128fSAndroid Build Coastguard Worker 	while (l < r) {
413*6a54128fSAndroid Build Coastguard Worker 		size_t m = l + (r - l) / 2;
414*6a54128fSAndroid Build Coastguard Worker 		const struct encrypted_file_range *range =
415*6a54128fSAndroid Build Coastguard Worker 			&info->file_ranges[m];
416*6a54128fSAndroid Build Coastguard Worker 
417*6a54128fSAndroid Build Coastguard Worker 		if (ino < range->first_ino)
418*6a54128fSAndroid Build Coastguard Worker 			r = m;
419*6a54128fSAndroid Build Coastguard Worker 		else if (ino > range->last_ino)
420*6a54128fSAndroid Build Coastguard Worker 			l = m + 1;
421*6a54128fSAndroid Build Coastguard Worker 		else
422*6a54128fSAndroid Build Coastguard Worker 			return range->policy_id;
423*6a54128fSAndroid Build Coastguard Worker 	}
424*6a54128fSAndroid Build Coastguard Worker 	return NO_ENCRYPTION_POLICY;
425*6a54128fSAndroid Build Coastguard Worker }
426*6a54128fSAndroid Build Coastguard Worker 
427*6a54128fSAndroid Build Coastguard Worker /* Destroy ctx->encrypted_files->policies */
destroy_encryption_policy_map(e2fsck_t ctx)428*6a54128fSAndroid Build Coastguard Worker void destroy_encryption_policy_map(e2fsck_t ctx)
429*6a54128fSAndroid Build Coastguard Worker {
430*6a54128fSAndroid Build Coastguard Worker 	struct encrypted_file_info *info = ctx->encrypted_files;
431*6a54128fSAndroid Build Coastguard Worker 
432*6a54128fSAndroid Build Coastguard Worker 	if (info) {
433*6a54128fSAndroid Build Coastguard Worker 		struct rb_root *policies = &info->policies;
434*6a54128fSAndroid Build Coastguard Worker 
435*6a54128fSAndroid Build Coastguard Worker 		while (!ext2fs_rb_empty_root(policies)) {
436*6a54128fSAndroid Build Coastguard Worker 			struct policy_map_entry *entry;
437*6a54128fSAndroid Build Coastguard Worker 
438*6a54128fSAndroid Build Coastguard Worker 			entry = ext2fs_rb_entry(policies->rb_node,
439*6a54128fSAndroid Build Coastguard Worker 						struct policy_map_entry, node);
440*6a54128fSAndroid Build Coastguard Worker 			ext2fs_rb_erase(&entry->node, policies);
441*6a54128fSAndroid Build Coastguard Worker 			ext2fs_free_mem(&entry);
442*6a54128fSAndroid Build Coastguard Worker 		}
443*6a54128fSAndroid Build Coastguard Worker 		info->next_policy_id = 0;
444*6a54128fSAndroid Build Coastguard Worker 	}
445*6a54128fSAndroid Build Coastguard Worker }
446*6a54128fSAndroid Build Coastguard Worker 
447*6a54128fSAndroid Build Coastguard Worker /* Destroy ctx->encrypted_files */
destroy_encrypted_file_info(e2fsck_t ctx)448*6a54128fSAndroid Build Coastguard Worker void destroy_encrypted_file_info(e2fsck_t ctx)
449*6a54128fSAndroid Build Coastguard Worker {
450*6a54128fSAndroid Build Coastguard Worker 	struct encrypted_file_info *info = ctx->encrypted_files;
451*6a54128fSAndroid Build Coastguard Worker 
452*6a54128fSAndroid Build Coastguard Worker 	if (info) {
453*6a54128fSAndroid Build Coastguard Worker 		destroy_encryption_policy_map(ctx);
454*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&info->file_ranges);
455*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&info);
456*6a54128fSAndroid Build Coastguard Worker 		ctx->encrypted_files = NULL;
457*6a54128fSAndroid Build Coastguard Worker 	}
458*6a54128fSAndroid Build Coastguard Worker }
459