summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPali Rohár <pali@kernel.org>2024-09-28 23:59:47 +0200
committerSteve French <stfrench@microsoft.com>2024-10-03 19:06:13 +0200
commit556ac52bb1e76cc28fd30aa117b42989965b3efd (patch)
tree6938e136aa7ea34a67e117e46388d5cb751535c4
parentcifs: Fix buffer overflow when parsing NFS reparse points (diff)
downloadlinux-556ac52bb1e76cc28fd30aa117b42989965b3efd.tar.xz
linux-556ac52bb1e76cc28fd30aa117b42989965b3efd.zip
cifs: Validate content of NFS reparse point buffer
Symlink target location stored in DataBuffer is encoded in UTF-16. So check that symlink DataBuffer length is non-zero and even number. And check that DataBuffer does not contain UTF-16 null codepoint because Linux cannot process symlink with null byte. DataBuffer for char and block devices is 8 bytes long as it contains two 32-bit numbers (major and minor). Add check for this. DataBuffer buffer for sockets and fifos zero-length. Add checks for this. Signed-off-by: Pali Rohár <pali@kernel.org> Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com>
-rw-r--r--fs/smb/client/reparse.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index 8ea7a848aa39..f0cfcf32de19 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -330,6 +330,18 @@ static int parse_reparse_posix(struct reparse_posix_data *buf,
switch ((type = le64_to_cpu(buf->InodeType))) {
case NFS_SPECFILE_LNK:
+ if (len == 0 || (len % 2)) {
+ cifs_dbg(VFS, "srv returned malformed nfs symlink buffer\n");
+ return -EIO;
+ }
+ /*
+ * Check that buffer does not contain UTF-16 null codepoint
+ * because Linux cannot process symlink with null byte.
+ */
+ if (UniStrnlen((wchar_t *)buf->DataBuffer, len/2) != len/2) {
+ cifs_dbg(VFS, "srv returned null byte in nfs symlink target location\n");
+ return -EIO;
+ }
data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer,
len, true,
cifs_sb->local_nls);
@@ -341,8 +353,19 @@ static int parse_reparse_posix(struct reparse_posix_data *buf,
break;
case NFS_SPECFILE_CHR:
case NFS_SPECFILE_BLK:
+ /* DataBuffer for block and char devices contains two 32-bit numbers */
+ if (len != 8) {
+ cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);
+ return -EIO;
+ }
+ break;
case NFS_SPECFILE_FIFO:
case NFS_SPECFILE_SOCK:
+ /* DataBuffer for fifos and sockets is empty */
+ if (len != 0) {
+ cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);
+ return -EIO;
+ }
break;
default:
cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n",