| From 6a54b2e002c9d00b398d35724c79f9fe0d9b38fb Mon Sep 17 00:00:00 2001 |
| From: Christoph Probst <kernel@probst.it> |
| Date: Tue, 7 May 2019 17:16:40 +0200 |
| Subject: cifs: fix strcat buffer overflow and reduce raciness in smb21_set_oplock_level() |
| |
| From: Christoph Probst <kernel@probst.it> |
| |
| commit 6a54b2e002c9d00b398d35724c79f9fe0d9b38fb upstream. |
| |
| Change strcat to strncpy in the "None" case to fix a buffer overflow |
| when cinode->oplock is reset to 0 by another thread accessing the same |
| cinode. It is never valid to append "None" to any other message. |
| |
| Consolidate multiple writes to cinode->oplock to reduce raciness. |
| |
| Signed-off-by: Christoph Probst <kernel@probst.it> |
| Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com> |
| Signed-off-by: Steve French <stfrench@microsoft.com> |
| CC: Stable <stable@vger.kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/cifs/smb2ops.c | 14 ++++++++------ |
| 1 file changed, 8 insertions(+), 6 deletions(-) |
| |
| --- a/fs/cifs/smb2ops.c |
| +++ b/fs/cifs/smb2ops.c |
| @@ -1413,26 +1413,28 @@ smb21_set_oplock_level(struct cifsInodeI |
| unsigned int epoch, bool *purge_cache) |
| { |
| char message[5] = {0}; |
| + unsigned int new_oplock = 0; |
| |
| oplock &= 0xFF; |
| if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE) |
| return; |
| |
| - cinode->oplock = 0; |
| if (oplock & SMB2_LEASE_READ_CACHING_HE) { |
| - cinode->oplock |= CIFS_CACHE_READ_FLG; |
| + new_oplock |= CIFS_CACHE_READ_FLG; |
| strcat(message, "R"); |
| } |
| if (oplock & SMB2_LEASE_HANDLE_CACHING_HE) { |
| - cinode->oplock |= CIFS_CACHE_HANDLE_FLG; |
| + new_oplock |= CIFS_CACHE_HANDLE_FLG; |
| strcat(message, "H"); |
| } |
| if (oplock & SMB2_LEASE_WRITE_CACHING_HE) { |
| - cinode->oplock |= CIFS_CACHE_WRITE_FLG; |
| + new_oplock |= CIFS_CACHE_WRITE_FLG; |
| strcat(message, "W"); |
| } |
| - if (!cinode->oplock) |
| - strcat(message, "None"); |
| + if (!new_oplock) |
| + strncpy(message, "None", sizeof(message)); |
| + |
| + cinode->oplock = new_oplock; |
| cifs_dbg(FYI, "%s Lease granted on inode %p\n", message, |
| &cinode->vfs_inode); |
| } |