Skip to content

Commit a0c5156

Browse files
Zhihao Chengrichardweinberger
authored andcommitted
ubifs: Fix AA deadlock when setting xattr for encrypted file
Following process: vfs_setxattr(host) ubifs_xattr_set down_write(host_ui->xattr_sem) <- lock first time create_xattr ubifs_new_inode(host) fscrypt_prepare_new_inode(host) fscrypt_policy_to_inherit(host) if (IS_ENCRYPTED(inode)) fscrypt_require_key(host) fscrypt_get_encryption_info(host) ubifs_xattr_get(host) down_read(host_ui->xattr_sem) <- AA deadlock , which may trigger an AA deadlock problem: [ 102.620871] INFO: task setfattr:1599 blocked for more than 10 seconds. [ 102.625298] Not tainted 5.19.0-rc7-00001-gb666b6823ce0-dirty #711 [ 102.628732] task:setfattr state:D stack: 0 pid: 1599 [ 102.628749] Call Trace: [ 102.628753] <TASK> [ 102.628776] __schedule+0x482/0x1060 [ 102.629964] schedule+0x92/0x1a0 [ 102.629976] rwsem_down_read_slowpath+0x287/0x8c0 [ 102.629996] down_read+0x84/0x170 [ 102.630585] ubifs_xattr_get+0xd1/0x370 [ubifs] [ 102.630730] ubifs_crypt_get_context+0x1f/0x30 [ubifs] [ 102.630791] fscrypt_get_encryption_info+0x7d/0x1c0 [ 102.630810] fscrypt_policy_to_inherit+0x56/0xc0 [ 102.630817] fscrypt_prepare_new_inode+0x35/0x160 [ 102.630830] ubifs_new_inode+0xcc/0x4b0 [ubifs] [ 102.630873] ubifs_xattr_set+0x591/0x9f0 [ubifs] [ 102.630961] xattr_set+0x8c/0x3e0 [ubifs] [ 102.631003] __vfs_setxattr+0x71/0xc0 [ 102.631026] vfs_setxattr+0x105/0x270 [ 102.631034] do_setxattr+0x6d/0x110 [ 102.631041] setxattr+0xa0/0xd0 [ 102.631087] __x64_sys_setxattr+0x2f/0x40 Fetch a reproducer in [Link]. Just like ext4 does, which skips encrypting for inode with EXT4_EA_INODE_FL flag. Stop encypting xattr inode for ubifs. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216260 Fixes: f4e3634 ("ubifs: Fix races between xattr_{set|get} ...") Fixes: d475a50 ("ubifs: Add skeleton for fscrypto") Signed-off-by: Zhihao Cheng <[email protected]> Signed-off-by: Richard Weinberger <[email protected]>
1 parent 713346c commit a0c5156

File tree

3 files changed

+16
-13
lines changed

3 files changed

+16
-13
lines changed

fs/ubifs/dir.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,14 @@ static int inherit_flags(const struct inode *dir, umode_t mode)
6868
* @c: UBIFS file-system description object
6969
* @dir: parent directory inode
7070
* @mode: inode mode flags
71+
* @is_xattr: whether the inode is xattr inode
7172
*
7273
* This function finds an unused inode number, allocates new inode and
7374
* initializes it. Returns new inode in case of success and an error code in
7475
* case of failure.
7576
*/
7677
struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
77-
umode_t mode)
78+
umode_t mode, bool is_xattr)
7879
{
7980
int err;
8081
struct inode *inode;
@@ -99,10 +100,12 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
99100
current_time(inode);
100101
inode->i_mapping->nrpages = 0;
101102

102-
err = fscrypt_prepare_new_inode(dir, inode, &encrypted);
103-
if (err) {
104-
ubifs_err(c, "fscrypt_prepare_new_inode failed: %i", err);
105-
goto out_iput;
103+
if (!is_xattr) {
104+
err = fscrypt_prepare_new_inode(dir, inode, &encrypted);
105+
if (err) {
106+
ubifs_err(c, "fscrypt_prepare_new_inode failed: %i", err);
107+
goto out_iput;
108+
}
106109
}
107110

108111
switch (mode & S_IFMT) {
@@ -309,7 +312,7 @@ static int ubifs_create(struct user_namespace *mnt_userns, struct inode *dir,
309312

310313
sz_change = CALC_DENT_SIZE(fname_len(&nm));
311314

312-
inode = ubifs_new_inode(c, dir, mode);
315+
inode = ubifs_new_inode(c, dir, mode, false);
313316
if (IS_ERR(inode)) {
314317
err = PTR_ERR(inode);
315318
goto out_fname;
@@ -370,7 +373,7 @@ static struct inode *create_whiteout(struct inode *dir, struct dentry *dentry)
370373
if (err)
371374
return ERR_PTR(err);
372375

373-
inode = ubifs_new_inode(c, dir, mode);
376+
inode = ubifs_new_inode(c, dir, mode, false);
374377
if (IS_ERR(inode)) {
375378
err = PTR_ERR(inode);
376379
goto out_free;
@@ -462,7 +465,7 @@ static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
462465
return err;
463466
}
464467

465-
inode = ubifs_new_inode(c, dir, mode);
468+
inode = ubifs_new_inode(c, dir, mode, false);
466469
if (IS_ERR(inode)) {
467470
err = PTR_ERR(inode);
468471
goto out_budg;
@@ -1004,7 +1007,7 @@ static int ubifs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
10041007

10051008
sz_change = CALC_DENT_SIZE(fname_len(&nm));
10061009

1007-
inode = ubifs_new_inode(c, dir, S_IFDIR | mode);
1010+
inode = ubifs_new_inode(c, dir, S_IFDIR | mode, false);
10081011
if (IS_ERR(inode)) {
10091012
err = PTR_ERR(inode);
10101013
goto out_fname;
@@ -1091,7 +1094,7 @@ static int ubifs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
10911094

10921095
sz_change = CALC_DENT_SIZE(fname_len(&nm));
10931096

1094-
inode = ubifs_new_inode(c, dir, mode);
1097+
inode = ubifs_new_inode(c, dir, mode, false);
10951098
if (IS_ERR(inode)) {
10961099
kfree(dev);
10971100
err = PTR_ERR(inode);
@@ -1173,7 +1176,7 @@ static int ubifs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
11731176

11741177
sz_change = CALC_DENT_SIZE(fname_len(&nm));
11751178

1176-
inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO);
1179+
inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO, false);
11771180
if (IS_ERR(inode)) {
11781181
err = PTR_ERR(inode);
11791182
goto out_fname;

fs/ubifs/ubifs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2026,7 +2026,7 @@ int ubifs_update_time(struct inode *inode, struct timespec64 *time, int flags);
20262026

20272027
/* dir.c */
20282028
struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
2029-
umode_t mode);
2029+
umode_t mode, bool is_xattr);
20302030
int ubifs_getattr(struct user_namespace *mnt_userns, const struct path *path, struct kstat *stat,
20312031
u32 request_mask, unsigned int flags);
20322032
int ubifs_check_dir_empty(struct inode *dir);

fs/ubifs/xattr.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
110110
if (err)
111111
return err;
112112

113-
inode = ubifs_new_inode(c, host, S_IFREG | S_IRWXUGO);
113+
inode = ubifs_new_inode(c, host, S_IFREG | S_IRWXUGO, true);
114114
if (IS_ERR(inode)) {
115115
err = PTR_ERR(inode);
116116
goto out_budg;

0 commit comments

Comments
 (0)