Message ID | 20200123164747.2713-1-marcelo.cerri@canonical.com |
---|---|
State | New |
Headers | show |
Series | [xenial:linux-azure] CIFS: Fix NULL-pointer dereference in smb2_push_mandatory_locks | expand |
On Thu, Jan 23, 2020 at 01:47:47PM -0300, Marcelo Henrique Cerri wrote: > From: Pavel Shilovsky <pshilov@microsoft.com> > > BugLink: https://bugs.launchpad.net/bugs/1860603 > > Currently when the client creates a cifsFileInfo structure for > a newly opened file, it allocates a list of byte-range locks > with a pointer to the new cfile and attaches this list to the > inode's lock list. The latter happens before initializing all > other fields, e.g. cfile->tlink. Thus a partially initialized > cifsFileInfo structure becomes available to other threads that > walk through the inode's lock list. One example of such a thread > may be an oplock break worker thread that tries to push all > cached byte-range locks. This causes NULL-pointer dereference > in smb2_push_mandatory_locks() when accessing cfile->tlink: > > [598428.945633] BUG: kernel NULL pointer dereference, address: 0000000000000038 > ... > [598428.945749] Workqueue: cifsoplockd cifs_oplock_break [cifs] > [598428.945793] RIP: 0010:smb2_push_mandatory_locks+0xd6/0x5a0 [cifs] > ... > [598428.945834] Call Trace: > [598428.945870] ? cifs_revalidate_mapping+0x45/0x90 [cifs] > [598428.945901] cifs_oplock_break+0x13d/0x450 [cifs] > [598428.945909] process_one_work+0x1db/0x380 > [598428.945914] worker_thread+0x4d/0x400 > [598428.945921] kthread+0x104/0x140 > [598428.945925] ? process_one_work+0x380/0x380 > [598428.945931] ? kthread_park+0x80/0x80 > [598428.945937] ret_from_fork+0x35/0x40 > > Fix this by reordering initialization steps of the cifsFileInfo > structure: initialize all the fields first and then add the new > byte-range lock list to the inode's lock list. > > Cc: Stable <stable@vger.kernel.org> > Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com> > Reviewed-by: Aurelien Aptel <aaptel@suse.com> > Signed-off-by: Steve French <stfrench@microsoft.com> > (cherry picked from commit 6f582b273ec23332074d970a7fb25bef835df71f) > Signed-off-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com> > --- > fs/cifs/file.c | 7 ++++--- > 1 file changed, 4 insertions(+), 3 deletions(-) > > diff --git a/fs/cifs/file.c b/fs/cifs/file.c > index efad56aeb161..9febc609cf2c 100644 > --- a/fs/cifs/file.c > +++ b/fs/cifs/file.c > @@ -312,9 +312,6 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, > INIT_LIST_HEAD(&fdlocks->locks); > fdlocks->cfile = cfile; > cfile->llist = fdlocks; > - cifs_down_write(&cinode->lock_sem); > - list_add(&fdlocks->llist, &cinode->llist); > - up_write(&cinode->lock_sem); > > cfile->count = 1; > cfile->pid = current->tgid; > @@ -338,6 +335,10 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, > oplock = 0; > } > > + cifs_down_write(&cinode->lock_sem); > + list_add(&fdlocks->llist, &cinode->llist); > + up_write(&cinode->lock_sem); > + > spin_lock(&tcon->open_file_lock); > if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock) > oplock = fid->pending_open->oplock; > -- > 2.20.1 > > > -- > kernel-team mailing list > kernel-team@lists.ubuntu.com > https://lists.ubuntu.com/mailman/listinfo/kernel-team Acked-by: Sultan Alsawaf <sultan.alsawaf@canonical.com>
On 23/01/2020 16:47, Marcelo Henrique Cerri wrote: > From: Pavel Shilovsky <pshilov@microsoft.com> > > BugLink: https://bugs.launchpad.net/bugs/1860603 > > Currently when the client creates a cifsFileInfo structure for > a newly opened file, it allocates a list of byte-range locks > with a pointer to the new cfile and attaches this list to the > inode's lock list. The latter happens before initializing all > other fields, e.g. cfile->tlink. Thus a partially initialized > cifsFileInfo structure becomes available to other threads that > walk through the inode's lock list. One example of such a thread > may be an oplock break worker thread that tries to push all > cached byte-range locks. This causes NULL-pointer dereference > in smb2_push_mandatory_locks() when accessing cfile->tlink: > > [598428.945633] BUG: kernel NULL pointer dereference, address: 0000000000000038 > ... > [598428.945749] Workqueue: cifsoplockd cifs_oplock_break [cifs] > [598428.945793] RIP: 0010:smb2_push_mandatory_locks+0xd6/0x5a0 [cifs] > ... > [598428.945834] Call Trace: > [598428.945870] ? cifs_revalidate_mapping+0x45/0x90 [cifs] > [598428.945901] cifs_oplock_break+0x13d/0x450 [cifs] > [598428.945909] process_one_work+0x1db/0x380 > [598428.945914] worker_thread+0x4d/0x400 > [598428.945921] kthread+0x104/0x140 > [598428.945925] ? process_one_work+0x380/0x380 > [598428.945931] ? kthread_park+0x80/0x80 > [598428.945937] ret_from_fork+0x35/0x40 > > Fix this by reordering initialization steps of the cifsFileInfo > structure: initialize all the fields first and then add the new > byte-range lock list to the inode's lock list. > > Cc: Stable <stable@vger.kernel.org> > Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com> > Reviewed-by: Aurelien Aptel <aaptel@suse.com> > Signed-off-by: Steve French <stfrench@microsoft.com> > (cherry picked from commit 6f582b273ec23332074d970a7fb25bef835df71f) > Signed-off-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com> > --- > fs/cifs/file.c | 7 ++++--- > 1 file changed, 4 insertions(+), 3 deletions(-) > > diff --git a/fs/cifs/file.c b/fs/cifs/file.c > index efad56aeb161..9febc609cf2c 100644 > --- a/fs/cifs/file.c > +++ b/fs/cifs/file.c > @@ -312,9 +312,6 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, > INIT_LIST_HEAD(&fdlocks->locks); > fdlocks->cfile = cfile; > cfile->llist = fdlocks; > - cifs_down_write(&cinode->lock_sem); > - list_add(&fdlocks->llist, &cinode->llist); > - up_write(&cinode->lock_sem); > > cfile->count = 1; > cfile->pid = current->tgid; > @@ -338,6 +335,10 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, > oplock = 0; > } > > + cifs_down_write(&cinode->lock_sem); > + list_add(&fdlocks->llist, &cinode->llist); > + up_write(&cinode->lock_sem); > + > spin_lock(&tcon->open_file_lock); > if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock) > oplock = fid->pending_open->oplock; > Yep, sane looking upstream cherry pick from 5.5, LGTM. Acked-by: Colin Ian King <colin.king@canonical.com>
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index efad56aeb161..9febc609cf2c 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -312,9 +312,6 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, INIT_LIST_HEAD(&fdlocks->locks); fdlocks->cfile = cfile; cfile->llist = fdlocks; - cifs_down_write(&cinode->lock_sem); - list_add(&fdlocks->llist, &cinode->llist); - up_write(&cinode->lock_sem); cfile->count = 1; cfile->pid = current->tgid; @@ -338,6 +335,10 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, oplock = 0; } + cifs_down_write(&cinode->lock_sem); + list_add(&fdlocks->llist, &cinode->llist); + up_write(&cinode->lock_sem); + spin_lock(&tcon->open_file_lock); if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock) oplock = fid->pending_open->oplock;