mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 15:41:52 +02:00
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: f4e3634a3b ("ubifs: Fix races between xattr_{set|get} ...")
Fixes: d475a50745 ("ubifs: Add skeleton for fscrypto")
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
parent
713346ca1d
commit
a0c5156573
|
|
@ -68,13 +68,14 @@ static int inherit_flags(const struct inode *dir, umode_t mode)
|
|||
* @c: UBIFS file-system description object
|
||||
* @dir: parent directory inode
|
||||
* @mode: inode mode flags
|
||||
* @is_xattr: whether the inode is xattr inode
|
||||
*
|
||||
* This function finds an unused inode number, allocates new inode and
|
||||
* initializes it. Returns new inode in case of success and an error code in
|
||||
* case of failure.
|
||||
*/
|
||||
struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
|
||||
umode_t mode)
|
||||
umode_t mode, bool is_xattr)
|
||||
{
|
||||
int err;
|
||||
struct inode *inode;
|
||||
|
|
@ -99,10 +100,12 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
|
|||
current_time(inode);
|
||||
inode->i_mapping->nrpages = 0;
|
||||
|
||||
err = fscrypt_prepare_new_inode(dir, inode, &encrypted);
|
||||
if (err) {
|
||||
ubifs_err(c, "fscrypt_prepare_new_inode failed: %i", err);
|
||||
goto out_iput;
|
||||
if (!is_xattr) {
|
||||
err = fscrypt_prepare_new_inode(dir, inode, &encrypted);
|
||||
if (err) {
|
||||
ubifs_err(c, "fscrypt_prepare_new_inode failed: %i", err);
|
||||
goto out_iput;
|
||||
}
|
||||
}
|
||||
|
||||
switch (mode & S_IFMT) {
|
||||
|
|
@ -309,7 +312,7 @@ static int ubifs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
|||
|
||||
sz_change = CALC_DENT_SIZE(fname_len(&nm));
|
||||
|
||||
inode = ubifs_new_inode(c, dir, mode);
|
||||
inode = ubifs_new_inode(c, dir, mode, false);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
goto out_fname;
|
||||
|
|
@ -370,7 +373,7 @@ static struct inode *create_whiteout(struct inode *dir, struct dentry *dentry)
|
|||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
inode = ubifs_new_inode(c, dir, mode);
|
||||
inode = ubifs_new_inode(c, dir, mode, false);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
goto out_free;
|
||||
|
|
@ -462,7 +465,7 @@ static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
|
|||
return err;
|
||||
}
|
||||
|
||||
inode = ubifs_new_inode(c, dir, mode);
|
||||
inode = ubifs_new_inode(c, dir, mode, false);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
goto out_budg;
|
||||
|
|
@ -1004,7 +1007,7 @@ static int ubifs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
|||
|
||||
sz_change = CALC_DENT_SIZE(fname_len(&nm));
|
||||
|
||||
inode = ubifs_new_inode(c, dir, S_IFDIR | mode);
|
||||
inode = ubifs_new_inode(c, dir, S_IFDIR | mode, false);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
goto out_fname;
|
||||
|
|
@ -1091,7 +1094,7 @@ static int ubifs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
|
|||
|
||||
sz_change = CALC_DENT_SIZE(fname_len(&nm));
|
||||
|
||||
inode = ubifs_new_inode(c, dir, mode);
|
||||
inode = ubifs_new_inode(c, dir, mode, false);
|
||||
if (IS_ERR(inode)) {
|
||||
kfree(dev);
|
||||
err = PTR_ERR(inode);
|
||||
|
|
@ -1173,7 +1176,7 @@ static int ubifs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
|
|||
|
||||
sz_change = CALC_DENT_SIZE(fname_len(&nm));
|
||||
|
||||
inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO);
|
||||
inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO, false);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
goto out_fname;
|
||||
|
|
|
|||
|
|
@ -2026,7 +2026,7 @@ int ubifs_update_time(struct inode *inode, struct timespec64 *time, int flags);
|
|||
|
||||
/* dir.c */
|
||||
struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
|
||||
umode_t mode);
|
||||
umode_t mode, bool is_xattr);
|
||||
int ubifs_getattr(struct user_namespace *mnt_userns, const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags);
|
||||
int ubifs_check_dir_empty(struct inode *dir);
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
inode = ubifs_new_inode(c, host, S_IFREG | S_IRWXUGO);
|
||||
inode = ubifs_new_inode(c, host, S_IFREG | S_IRWXUGO, true);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
goto out_budg;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user