Skip to content

Commit fea3043

Browse files
committed
Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 updates from Ted Ts'o: "Various bug fixes and cleanups for ext4. In particular, move the crypto related fucntions from fs/ext4/super.c into a new fs/ext4/crypto.c, and fix a number of bugs found by fuzzers and error injection tools" * tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (25 commits) ext4: only allow test_dummy_encryption when supported ext4: fix bug_on in __es_tree_search ext4: avoid cycles in directory h-tree ext4: verify dir block before splitting it ext4: filter out EXT4_FC_REPLAY from on-disk superblock field s_state ext4: fix bug_on in ext4_writepages ext4: refactor and move ext4_ioctl_get_encryption_pwsalt() ext4: cleanup function defs from ext4.h into crypto.c ext4: move ext4 crypto code to its own file crypto.c ext4: fix memory leak in parse_apply_sb_mount_options() ext4: reject the 'commit' option on ext2 filesystems ext4: remove duplicated #include of dax.h in inode.c ext4: fix race condition between ext4_write and ext4_convert_inline_data ext4: convert symlink external data block mapping to bdev ext4: add nowait mode for ext4_getblk() ext4: fix journal_ioprio mount option handling ext4: mark group as trimmed only if it was fully scanned ext4: fix use-after-free in ext4_rename_dir_prepare ext4: add unmount filesystem message ext4: remove unnecessary conditionals ...
2 parents 7208c98 + 5f41fda commit fea3043

File tree

14 files changed

+564
-429
lines changed

14 files changed

+564
-429
lines changed

fs/ext4/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
1717
ext4-inode-test-objs += inode-test.o
1818
obj-$(CONFIG_EXT4_KUNIT_TESTS) += ext4-inode-test.o
1919
ext4-$(CONFIG_FS_VERITY) += verity.o
20+
ext4-$(CONFIG_FS_ENCRYPTION) += crypto.o

fs/ext4/crypto.c

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/quotaops.h>
4+
#include <linux/uuid.h>
5+
6+
#include "ext4.h"
7+
#include "xattr.h"
8+
#include "ext4_jbd2.h"
9+
10+
static void ext4_fname_from_fscrypt_name(struct ext4_filename *dst,
11+
const struct fscrypt_name *src)
12+
{
13+
memset(dst, 0, sizeof(*dst));
14+
15+
dst->usr_fname = src->usr_fname;
16+
dst->disk_name = src->disk_name;
17+
dst->hinfo.hash = src->hash;
18+
dst->hinfo.minor_hash = src->minor_hash;
19+
dst->crypto_buf = src->crypto_buf;
20+
}
21+
22+
int ext4_fname_setup_filename(struct inode *dir, const struct qstr *iname,
23+
int lookup, struct ext4_filename *fname)
24+
{
25+
struct fscrypt_name name;
26+
int err;
27+
28+
err = fscrypt_setup_filename(dir, iname, lookup, &name);
29+
if (err)
30+
return err;
31+
32+
ext4_fname_from_fscrypt_name(fname, &name);
33+
34+
#if IS_ENABLED(CONFIG_UNICODE)
35+
err = ext4_fname_setup_ci_filename(dir, iname, fname);
36+
#endif
37+
return err;
38+
}
39+
40+
int ext4_fname_prepare_lookup(struct inode *dir, struct dentry *dentry,
41+
struct ext4_filename *fname)
42+
{
43+
struct fscrypt_name name;
44+
int err;
45+
46+
err = fscrypt_prepare_lookup(dir, dentry, &name);
47+
if (err)
48+
return err;
49+
50+
ext4_fname_from_fscrypt_name(fname, &name);
51+
52+
#if IS_ENABLED(CONFIG_UNICODE)
53+
err = ext4_fname_setup_ci_filename(dir, &dentry->d_name, fname);
54+
#endif
55+
return err;
56+
}
57+
58+
void ext4_fname_free_filename(struct ext4_filename *fname)
59+
{
60+
struct fscrypt_name name;
61+
62+
name.crypto_buf = fname->crypto_buf;
63+
fscrypt_free_filename(&name);
64+
65+
fname->crypto_buf.name = NULL;
66+
fname->usr_fname = NULL;
67+
fname->disk_name.name = NULL;
68+
69+
#if IS_ENABLED(CONFIG_UNICODE)
70+
kfree(fname->cf_name.name);
71+
fname->cf_name.name = NULL;
72+
#endif
73+
}
74+
75+
static bool uuid_is_zero(__u8 u[16])
76+
{
77+
int i;
78+
79+
for (i = 0; i < 16; i++)
80+
if (u[i])
81+
return false;
82+
return true;
83+
}
84+
85+
int ext4_ioctl_get_encryption_pwsalt(struct file *filp, void __user *arg)
86+
{
87+
struct super_block *sb = file_inode(filp)->i_sb;
88+
struct ext4_sb_info *sbi = EXT4_SB(sb);
89+
int err, err2;
90+
handle_t *handle;
91+
92+
if (!ext4_has_feature_encrypt(sb))
93+
return -EOPNOTSUPP;
94+
95+
if (uuid_is_zero(sbi->s_es->s_encrypt_pw_salt)) {
96+
err = mnt_want_write_file(filp);
97+
if (err)
98+
return err;
99+
handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1);
100+
if (IS_ERR(handle)) {
101+
err = PTR_ERR(handle);
102+
goto pwsalt_err_exit;
103+
}
104+
err = ext4_journal_get_write_access(handle, sb, sbi->s_sbh,
105+
EXT4_JTR_NONE);
106+
if (err)
107+
goto pwsalt_err_journal;
108+
lock_buffer(sbi->s_sbh);
109+
generate_random_uuid(sbi->s_es->s_encrypt_pw_salt);
110+
ext4_superblock_csum_set(sb);
111+
unlock_buffer(sbi->s_sbh);
112+
err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
113+
pwsalt_err_journal:
114+
err2 = ext4_journal_stop(handle);
115+
if (err2 && !err)
116+
err = err2;
117+
pwsalt_err_exit:
118+
mnt_drop_write_file(filp);
119+
if (err)
120+
return err;
121+
}
122+
123+
if (copy_to_user(arg, sbi->s_es->s_encrypt_pw_salt, 16))
124+
return -EFAULT;
125+
return 0;
126+
}
127+
128+
static int ext4_get_context(struct inode *inode, void *ctx, size_t len)
129+
{
130+
return ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
131+
EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len);
132+
}
133+
134+
static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
135+
void *fs_data)
136+
{
137+
handle_t *handle = fs_data;
138+
int res, res2, credits, retries = 0;
139+
140+
/*
141+
* Encrypting the root directory is not allowed because e2fsck expects
142+
* lost+found to exist and be unencrypted, and encrypting the root
143+
* directory would imply encrypting the lost+found directory as well as
144+
* the filename "lost+found" itself.
145+
*/
146+
if (inode->i_ino == EXT4_ROOT_INO)
147+
return -EPERM;
148+
149+
if (WARN_ON_ONCE(IS_DAX(inode) && i_size_read(inode)))
150+
return -EINVAL;
151+
152+
if (ext4_test_inode_flag(inode, EXT4_INODE_DAX))
153+
return -EOPNOTSUPP;
154+
155+
res = ext4_convert_inline_data(inode);
156+
if (res)
157+
return res;
158+
159+
/*
160+
* If a journal handle was specified, then the encryption context is
161+
* being set on a new inode via inheritance and is part of a larger
162+
* transaction to create the inode. Otherwise the encryption context is
163+
* being set on an existing inode in its own transaction. Only in the
164+
* latter case should the "retry on ENOSPC" logic be used.
165+
*/
166+
167+
if (handle) {
168+
res = ext4_xattr_set_handle(handle, inode,
169+
EXT4_XATTR_INDEX_ENCRYPTION,
170+
EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
171+
ctx, len, 0);
172+
if (!res) {
173+
ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
174+
ext4_clear_inode_state(inode,
175+
EXT4_STATE_MAY_INLINE_DATA);
176+
/*
177+
* Update inode->i_flags - S_ENCRYPTED will be enabled,
178+
* S_DAX may be disabled
179+
*/
180+
ext4_set_inode_flags(inode, false);
181+
}
182+
return res;
183+
}
184+
185+
res = dquot_initialize(inode);
186+
if (res)
187+
return res;
188+
retry:
189+
res = ext4_xattr_set_credits(inode, len, false /* is_create */,
190+
&credits);
191+
if (res)
192+
return res;
193+
194+
handle = ext4_journal_start(inode, EXT4_HT_MISC, credits);
195+
if (IS_ERR(handle))
196+
return PTR_ERR(handle);
197+
198+
res = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_ENCRYPTION,
199+
EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
200+
ctx, len, 0);
201+
if (!res) {
202+
ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
203+
/*
204+
* Update inode->i_flags - S_ENCRYPTED will be enabled,
205+
* S_DAX may be disabled
206+
*/
207+
ext4_set_inode_flags(inode, false);
208+
res = ext4_mark_inode_dirty(handle, inode);
209+
if (res)
210+
EXT4_ERROR_INODE(inode, "Failed to mark inode dirty");
211+
}
212+
res2 = ext4_journal_stop(handle);
213+
214+
if (res == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
215+
goto retry;
216+
if (!res)
217+
res = res2;
218+
return res;
219+
}
220+
221+
static const union fscrypt_policy *ext4_get_dummy_policy(struct super_block *sb)
222+
{
223+
return EXT4_SB(sb)->s_dummy_enc_policy.policy;
224+
}
225+
226+
static bool ext4_has_stable_inodes(struct super_block *sb)
227+
{
228+
return ext4_has_feature_stable_inodes(sb);
229+
}
230+
231+
static void ext4_get_ino_and_lblk_bits(struct super_block *sb,
232+
int *ino_bits_ret, int *lblk_bits_ret)
233+
{
234+
*ino_bits_ret = 8 * sizeof(EXT4_SB(sb)->s_es->s_inodes_count);
235+
*lblk_bits_ret = 8 * sizeof(ext4_lblk_t);
236+
}
237+
238+
const struct fscrypt_operations ext4_cryptops = {
239+
.key_prefix = "ext4:",
240+
.get_context = ext4_get_context,
241+
.set_context = ext4_set_context,
242+
.get_dummy_policy = ext4_get_dummy_policy,
243+
.empty_dir = ext4_empty_dir,
244+
.has_stable_inodes = ext4_has_stable_inodes,
245+
.get_ino_and_lblk_bits = ext4_get_ino_and_lblk_bits,
246+
};

fs/ext4/dir.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ struct fname {
412412
};
413413

414414
/*
415-
* This functoin implements a non-recursive way of freeing all of the
415+
* This function implements a non-recursive way of freeing all of the
416416
* nodes in the red-black tree.
417417
*/
418418
static void free_rb_tree_fname(struct rb_root *root)
@@ -515,7 +515,7 @@ int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
515515

516516
/*
517517
* This is a helper function for ext4_dx_readdir. It calls filldir
518-
* for all entres on the fname linked list. (Normally there is only
518+
* for all entries on the fname linked list. (Normally there is only
519519
* one entry on the linked list, unless there are 62 bit hash collisions.)
520520
*/
521521
static int call_filldir(struct file *file, struct dir_context *ctx,
@@ -648,7 +648,7 @@ int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, void *buf,
648648
unsigned int offset = 0;
649649
char *top;
650650

651-
de = (struct ext4_dir_entry_2 *)buf;
651+
de = buf;
652652
top = buf + buf_size;
653653
while ((char *) de < top) {
654654
if (ext4_check_dir_entry(dir, NULL, de, bh,

fs/ext4/ext4.h

Lines changed: 16 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,8 @@ enum {
673673
/* Caller will submit data before dropping transaction handle. This
674674
* allows jbd2 to avoid submitting data before commit. */
675675
#define EXT4_GET_BLOCKS_IO_SUBMIT 0x0400
676+
/* Caller is in the atomic contex, find extent if it has been cached */
677+
#define EXT4_GET_BLOCKS_CACHED_NOWAIT 0x0800
676678

677679
/*
678680
* The bit position of these flags must not overlap with any of the
@@ -1440,12 +1442,6 @@ struct ext4_super_block {
14401442

14411443
#ifdef __KERNEL__
14421444

1443-
#ifdef CONFIG_FS_ENCRYPTION
1444-
#define DUMMY_ENCRYPTION_ENABLED(sbi) ((sbi)->s_dummy_enc_policy.policy != NULL)
1445-
#else
1446-
#define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
1447-
#endif
1448-
14491445
/* Number of quota types we support */
14501446
#define EXT4_MAXQUOTAS 3
14511447

@@ -2731,74 +2727,20 @@ extern int ext4_fname_setup_ci_filename(struct inode *dir,
27312727
struct ext4_filename *fname);
27322728
#endif
27332729

2730+
/* ext4 encryption related stuff goes here crypto.c */
27342731
#ifdef CONFIG_FS_ENCRYPTION
2735-
static inline void ext4_fname_from_fscrypt_name(struct ext4_filename *dst,
2736-
const struct fscrypt_name *src)
2737-
{
2738-
memset(dst, 0, sizeof(*dst));
2739-
2740-
dst->usr_fname = src->usr_fname;
2741-
dst->disk_name = src->disk_name;
2742-
dst->hinfo.hash = src->hash;
2743-
dst->hinfo.minor_hash = src->minor_hash;
2744-
dst->crypto_buf = src->crypto_buf;
2745-
}
2746-
2747-
static inline int ext4_fname_setup_filename(struct inode *dir,
2748-
const struct qstr *iname,
2749-
int lookup,
2750-
struct ext4_filename *fname)
2751-
{
2752-
struct fscrypt_name name;
2753-
int err;
2754-
2755-
err = fscrypt_setup_filename(dir, iname, lookup, &name);
2756-
if (err)
2757-
return err;
2758-
2759-
ext4_fname_from_fscrypt_name(fname, &name);
2760-
2761-
#if IS_ENABLED(CONFIG_UNICODE)
2762-
err = ext4_fname_setup_ci_filename(dir, iname, fname);
2763-
#endif
2764-
return err;
2765-
}
2732+
extern const struct fscrypt_operations ext4_cryptops;
27662733

2767-
static inline int ext4_fname_prepare_lookup(struct inode *dir,
2768-
struct dentry *dentry,
2769-
struct ext4_filename *fname)
2770-
{
2771-
struct fscrypt_name name;
2772-
int err;
2734+
int ext4_fname_setup_filename(struct inode *dir, const struct qstr *iname,
2735+
int lookup, struct ext4_filename *fname);
27732736

2774-
err = fscrypt_prepare_lookup(dir, dentry, &name);
2775-
if (err)
2776-
return err;
2737+
int ext4_fname_prepare_lookup(struct inode *dir, struct dentry *dentry,
2738+
struct ext4_filename *fname);
27772739

2778-
ext4_fname_from_fscrypt_name(fname, &name);
2740+
void ext4_fname_free_filename(struct ext4_filename *fname);
27792741

2780-
#if IS_ENABLED(CONFIG_UNICODE)
2781-
err = ext4_fname_setup_ci_filename(dir, &dentry->d_name, fname);
2782-
#endif
2783-
return err;
2784-
}
2785-
2786-
static inline void ext4_fname_free_filename(struct ext4_filename *fname)
2787-
{
2788-
struct fscrypt_name name;
2742+
int ext4_ioctl_get_encryption_pwsalt(struct file *filp, void __user *arg);
27892743

2790-
name.crypto_buf = fname->crypto_buf;
2791-
fscrypt_free_filename(&name);
2792-
2793-
fname->crypto_buf.name = NULL;
2794-
fname->usr_fname = NULL;
2795-
fname->disk_name.name = NULL;
2796-
2797-
#if IS_ENABLED(CONFIG_UNICODE)
2798-
kfree(fname->cf_name.name);
2799-
fname->cf_name.name = NULL;
2800-
#endif
2801-
}
28022744
#else /* !CONFIG_FS_ENCRYPTION */
28032745
static inline int ext4_fname_setup_filename(struct inode *dir,
28042746
const struct qstr *iname,
@@ -2831,6 +2773,12 @@ static inline void ext4_fname_free_filename(struct ext4_filename *fname)
28312773
fname->cf_name.name = NULL;
28322774
#endif
28332775
}
2776+
2777+
static inline int ext4_ioctl_get_encryption_pwsalt(struct file *filp,
2778+
void __user *arg)
2779+
{
2780+
return -EOPNOTSUPP;
2781+
}
28342782
#endif /* !CONFIG_FS_ENCRYPTION */
28352783

28362784
/* dir.c */

0 commit comments

Comments
 (0)