]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
cifs: Validate content of NFS reparse point buffer
authorPali Rohár <pali@kernel.org>
Sat, 28 Sep 2024 21:59:47 +0000 (23:59 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 1 Nov 2024 01:02:34 +0000 (02:02 +0100)
[ Upstream commit 556ac52bb1e76cc28fd30aa117b42989965b3efd ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/smb/client/reparse.c

index ad0e0de9a165d4bae8e7780071a8bdf2a3b8024d..7429b96a6ae5ef39930c96d83772aec7d5f1ae94 100644 (file)
@@ -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);
@@ -340,8 +352,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",