cifs: Limit memory used by lock request calls to a page
authorRoss Lagerwall <ross.lagerwall@citrix.com>
Tue, 8 Jan 2019 18:30:56 +0000 (18:30 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Feb 2019 09:20:51 +0000 (10:20 +0100)
[ Upstream commit 92a8109e4d3a34fb6b115c9098b51767dc933444 ]

The code tries to allocate a contiguous buffer with a size supplied by
the server (maxBuf). This could fail if memory is fragmented since it
results in high order allocations for commonly used server
implementations. It is also wasteful since there are probably
few locks in the usual case. Limit the buffer to be no larger than a
page to avoid memory allocation failures due to fragmentation.

Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/cifs/file.c
fs/cifs/smb2file.c

index 1e176e11dbfac241ea38eb8b99d90c7f8ae399d4..852d7d1dcbbd3772c72258d0c1d20fd27298d534 100644 (file)
@@ -1128,6 +1128,10 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
                return -EINVAL;
        }
 
+       BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) >
+                    PAGE_SIZE);
+       max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr),
+                       PAGE_SIZE);
        max_num = (max_buf - sizeof(struct smb_hdr)) /
                                                sizeof(LOCKING_ANDX_RANGE);
        buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
@@ -1466,6 +1470,10 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
        if (max_buf < (sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE)))
                return -EINVAL;
 
+       BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) >
+                    PAGE_SIZE);
+       max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr),
+                       PAGE_SIZE);
        max_num = (max_buf - sizeof(struct smb_hdr)) /
                                                sizeof(LOCKING_ANDX_RANGE);
        buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
index 79078533f807097b541906d15dd3631d932143b5..1add404618f060ca7a691a395e815af1dfa69784 100644 (file)
@@ -130,6 +130,8 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
        if (max_buf < sizeof(struct smb2_lock_element))
                return -EINVAL;
 
+       BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE);
+       max_buf = min_t(unsigned int, max_buf, PAGE_SIZE);
        max_num = max_buf / sizeof(struct smb2_lock_element);
        buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
        if (!buf)
@@ -266,6 +268,8 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
                return -EINVAL;
        }
 
+       BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE);
+       max_buf = min_t(unsigned int, max_buf, PAGE_SIZE);
        max_num = max_buf / sizeof(struct smb2_lock_element);
        buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
        if (!buf) {