Merged into cifs-2.6.git for-next On Wed, Nov 27, 2019 at 6:18 PM Pavel Shilovsky <piastryyy@xxxxxxxxx> wrote: > > 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@xxxxxxxxxxxxxxx> > Signed-off-by: Pavel Shilovsky <pshilov@xxxxxxxxxxxxx> > --- > 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 520fbe4d42b9..069635ec9d94 100644 > --- a/fs/cifs/file.c > +++ b/fs/cifs/file.c > @@ -313,9 +313,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; > @@ -339,6 +336,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.17.1 > -- Thanks, Steve