[linux-cifs-client] [patch] prevent slab corruption by fixing race codition in cifs
Shirish Pargaonkar
shirishpargaonkar at gmail.com
Mon Aug 17 14:31:43 MDT 2009
Jeff,
Hope this works.
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 6084d63..9ad3258 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -349,6 +349,7 @@ struct cifsFileInfo {
struct mutex lock_mutex;
struct list_head llist; /* list of byte range locks we have. */
bool closePend:1; /* file is marked to close */
+ bool closed:1; /* file is closed */
bool invalidHandle:1; /* file closed via session abend */
bool messageMode:1; /* for pipes: message vs byte mode */
atomic_t wrtPending; /* handle in use - defer close */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index c34b7f8..f1ae25c 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -698,7 +698,10 @@ int cifs_close(struct inode *inode, struct file *file)
msleep(timeout);
timeout *= 8;
}
- kfree(file->private_data);
+ if (atomic_read(&pSMBFile->wrtPending) == 0)
+ kfree(file->private_data);
+ else
+ pSMBFile->closed = true;
file->private_data = NULL;
} else
rc = -EBADF;
@@ -1293,7 +1296,10 @@ refind_writable:
else { /* start over in case this was deleted */
/* since the list could be modified */
read_lock(&GlobalSMBSeslock);
- atomic_dec(&open_file->wrtPending);
+ if (atomic_dec_and_test(
+ &open_file->wrtPending)
+ && open_file->closed)
+ kfree(open_file);
goto refind_writable;
}
}
@@ -1309,10 +1315,12 @@ refind_writable:
read_lock(&GlobalSMBSeslock);
/* can not use this handle, no write
pending on this one after all */
- atomic_dec(&open_file->wrtPending);
-
- if (open_file->closePend) /* list could have changed */
+ if (atomic_dec_and_test(&open_file->wrtPending)
+ && open_file->closed) {
+ kfree(open_file);
goto refind_writable;
+ } else if (open_file->closePend) /* list could */
+ goto refind_writable; /* have changed */
/* else we simply continue to the next entry. Thus
we do not loop on reopen errors. If we
can not reopen the file, for example if we
@@ -1373,7 +1381,9 @@ static int cifs_partialpagewrite(struct page
*page, unsigned from, unsigned to)
if (open_file) {
bytes_written = cifs_write(open_file->pfile, write_data,
to-from, &offset);
- atomic_dec(&open_file->wrtPending);
+ if (atomic_dec_and_test(&open_file->wrtPending)
+ && open_file->closed)
+ kfree(open_file);
/* Does mm or vfs already set times? */
inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
if ((bytes_written > 0) && (offset))
@@ -1562,7 +1572,9 @@ retry:
bytes_to_write, offset,
&bytes_written, iov, n_iov,
long_op);
- atomic_dec(&open_file->wrtPending);
+ if (atomic_dec_and_test(&open_file->wrtPending)
+ && open_file->closed)
+ kfree(open_file);
cifs_update_eof(cifsi, offset, bytes_written);
if (rc || bytes_written < bytes_to_write) {
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 82d8383..3b4c27d 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -799,8 +799,11 @@ set_via_filehandle:
if (open_file == NULL)
CIFSSMBClose(xid, pTcon, netfid);
- else
- atomic_dec(&open_file->wrtPending);
+ else {
+ if (atomic_dec_and_test(&open_file->wrtPending)
+ && open_file->closed)
+ kfree(open_file);
+ }
out:
return rc;
}
@@ -1635,7 +1638,9 @@ cifs_set_file_size(struct inode *inode, struct
iattr *attrs,
__u32 npid = open_file->pid;
rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
npid, false);
- atomic_dec(&open_file->wrtPending);
+ if (atomic_dec_and_test(&open_file->wrtPending)
+ && open_file->closed)
+ kfree(open_file);
cFYI(1, ("SetFSize for attrs rc = %d", rc));
if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
unsigned int bytes_written;
@@ -1790,7 +1795,9 @@ cifs_setattr_unix(struct dentry *direntry,
struct iattr *attrs)
u16 nfid = open_file->netfid;
u32 npid = open_file->pid;
rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
- atomic_dec(&open_file->wrtPending);
+ if (atomic_dec_and_test(&open_file->wrtPending)
+ && open_file->closed)
+ kfree(open_file);
} else {
rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
cifs_sb->local_nls,
signed-off by: Shirish Pargaonkar <shirishpargaonkar at gmail.com>
On Mon, Aug 17, 2009 at 2:50 PM, Jeff Layton<jlayton at redhat.com> wrote:
> On Sun, 16 Aug 2009 11:38:57 -0500
> Shirish Pargaonkar <shirishpargaonkar at gmail.com> wrote:
>
>> This patch prevents a slab corruption like this. During heavy stress,
>> it is possible that
>> cifs_close will free up cifsFileInfo while due to delayed writes,
>> wrtPending of that
>> cifsFileInfo gets updated (decremented), cifsFileInfo either freed or
>> freed and allocated to another process.
>>
>>
>> Slab corruption: start=ffff8101e28e3818, len=256
>> Redzone: 0x5a2cf071/0x5a2cf071.
>> Last user: [<ffffffff88276ec4>](cifs_close+0x224/0x2c2 [cifs])
>> 060: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6a 6b 6b 6b
>> Prev obj: start=ffff8101e28e3700, len=256
>> Redzone: 0x170fc2a5/0x170fc2a5.
>> Last user: [<ffffffff882784fa>](cifs_open+0x348/0x6d9 [cifs])
>> 000: b8 d3 44 e2 01 81 ff ff a0 e2 c7 e1 01 81 ff ff
>> 010: 68 f5 fa dc 01 81 ff ff 10 47 d4 dd 01 81 ff ff
>> Next obj: start=ffff8101e28e3930, len=256
>> Redzone: 0x170fc2a5/0x170fc2a5.
>> Last user: [<ffffffff882784fa>](cifs_open+0x348/0x6d9 [cifs])
>> 000: 18 b8 2a e3 01 81 ff ff b8 a3 5a e0 01 81 ff ff
>> 010: 68 f5 36 65 02 81 ff ff 40 99 a1 dc 01 81 ff ff
>
> Can you resend this patch with it inlined into the email? I can't
> reasonably comment on it with it sent as a binary attachment.
>
> Thanks,
> --
> Jeff Layton <jlayton at redhat.com>
>
More information about the linux-cifs-client
mailing list