From: Greg Kroah-Hartman Date: Sun, 2 Feb 2020 20:50:11 +0000 (+0000) Subject: 4.4-stable patches X-Git-Tag: v5.5.2~43 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0689affbe4af9a2e73b92d4f7367ed469df4be67;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: vfs-fix-do_last-regression.patch --- diff --git a/queue-4.4/series b/queue-4.4/series index 21e5ade4971..7b632e78a12 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -20,3 +20,4 @@ atm-eni-fix-uninitialized-variable-warning.patch usb-storage-disable-uas-on-jmicron-sata-enclosure.patch net_sched-ematch-reject-invalid-tcf_em_simple.patch crypto-af_alg-use-bh_lock_sock-in-sk_destruct.patch +vfs-fix-do_last-regression.patch diff --git a/queue-4.4/vfs-fix-do_last-regression.patch b/queue-4.4/vfs-fix-do_last-regression.patch new file mode 100644 index 00000000000..e26e79f9ba8 --- /dev/null +++ b/queue-4.4/vfs-fix-do_last-regression.patch @@ -0,0 +1,63 @@ +From 6404674acd596de41fd3ad5f267b4525494a891a Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Sat, 1 Feb 2020 16:26:45 +0000 +Subject: vfs: fix do_last() regression + +From: Al Viro + +commit 6404674acd596de41fd3ad5f267b4525494a891a upstream. + +Brown paperbag time: fetching ->i_uid/->i_mode really should've been +done from nd->inode. I even suggested that, but the reason for that has +slipped through the cracks and I went for dir->d_inode instead - made +for more "obvious" patch. + +Analysis: + + - at the entry into do_last() and all the way to step_into(): dir (aka + nd->path.dentry) is known not to have been freed; so's nd->inode and + it's equal to dir->d_inode unless we are already doomed to -ECHILD. + inode of the file to get opened is not known. + + - after step_into(): inode of the file to get opened is known; dir + might be pointing to freed memory/be negative/etc. + + - at the call of may_create_in_sticky(): guaranteed to be out of RCU + mode; inode of the file to get opened is known and pinned; dir might + be garbage. + +The last was the reason for the original patch. Except that at the +do_last() entry we can be in RCU mode and it is possible that +nd->path.dentry->d_inode has already changed under us. + +In that case we are going to fail with -ECHILD, but we need to be +careful; nd->inode is pointing to valid struct inode and it's the same +as nd->path.dentry->d_inode in "won't fail with -ECHILD" case, so we +should use that. + +Reported-by: "Rantala, Tommi T. (Nokia - FI/Espoo)" +Reported-by: syzbot+190005201ced78a74ad6@syzkaller.appspotmail.com +Wearing-brown-paperbag: Al Viro +Cc: stable@kernel.org +Fixes: d0cb50185ae9 ("do_last(): fetch directory ->i_mode and ->i_uid before it's too late") +Signed-off-by: Al Viro +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/namei.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -3060,8 +3060,8 @@ static int do_last(struct nameidata *nd, + int *opened) + { + struct dentry *dir = nd->path.dentry; +- kuid_t dir_uid = dir->d_inode->i_uid; +- umode_t dir_mode = dir->d_inode->i_mode; ++ kuid_t dir_uid = nd->inode->i_uid; ++ umode_t dir_mode = nd->inode->i_mode; + int open_flag = op->open_flag; + bool will_truncate = (open_flag & O_TRUNC) != 0; + bool got_write = false;