smb: client: fix potential broken compound request
authorPaulo Alcantara <pc@manguebit.com>
Thu, 25 Jan 2024 20:04:05 +0000 (17:04 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 25 May 2024 14:22:48 +0000 (16:22 +0200)
[ Upstream commit 6914d288c63682e20e0f6e1e0b8e8f5847012d67 ]

Now that smb2_compound_op() can accept up to 5 commands in a single
compound request, set the appropriate NextCommand and related flags to
all subsequent commands as well as handling the case where a valid
@cfile is passed and therefore skipping create and close requests in
the compound chain.

This fix a potential broken compound request that could be sent from
smb2_get_reparse_inode() if the client found a valid open
file (@cfile) prior to calling smb2_compound_op().

Signed-off-by: Paulo Alcantara <pc@manguebit.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/smb/client/smb2inode.c

index add90eb8fc16556d280a0dcce3b99463f8da79ff..33f3fffcb827707caa1e1a3c2d6108b1ad1858a4 100644 (file)
@@ -223,14 +223,13 @@ replay_again:
                                                          SMB2_O_INFO_FILE, 0,
                                                          sizeof(struct smb2_file_all_info) +
                                                          PATH_MAX * 2, 0, NULL);
-                               if (!rc) {
-                                       smb2_set_next_command(tcon, &rqst[num_rqst]);
-                                       smb2_set_related(&rqst[num_rqst]);
-                               }
                        }
-
-                       if (rc)
+                       if (!rc && (!cfile || num_rqst > 1)) {
+                               smb2_set_next_command(tcon, &rqst[num_rqst]);
+                               smb2_set_related(&rqst[num_rqst]);
+                       } else if (rc) {
                                goto finished;
+                       }
                        num_rqst++;
                        trace_smb3_query_info_compound_enter(xid, ses->Suid,
                                                             tcon->tid, full_path);
@@ -260,14 +259,13 @@ replay_again:
                                                          sizeof(struct smb311_posix_qinfo *) +
                                                          (PATH_MAX * 2) +
                                                          (sizeof(struct cifs_sid) * 2), 0, NULL);
-                               if (!rc) {
-                                       smb2_set_next_command(tcon, &rqst[num_rqst]);
-                                       smb2_set_related(&rqst[num_rqst]);
-                               }
                        }
-
-                       if (rc)
+                       if (!rc && (!cfile || num_rqst > 1)) {
+                               smb2_set_next_command(tcon, &rqst[num_rqst]);
+                               smb2_set_related(&rqst[num_rqst]);
+                       } else if (rc) {
                                goto finished;
+                       }
                        num_rqst++;
                        trace_smb3_posix_query_info_compound_enter(xid, ses->Suid,
                                                                   tcon->tid, full_path);
@@ -325,13 +323,13 @@ replay_again:
                                                        FILE_END_OF_FILE_INFORMATION,
                                                        SMB2_O_INFO_FILE, 0,
                                                        data, size);
-                               if (!rc) {
-                                       smb2_set_next_command(tcon, &rqst[num_rqst]);
-                                       smb2_set_related(&rqst[num_rqst]);
-                               }
                        }
-                       if (rc)
+                       if (!rc && (!cfile || num_rqst > 1)) {
+                               smb2_set_next_command(tcon, &rqst[num_rqst]);
+                               smb2_set_related(&rqst[num_rqst]);
+                       } else if (rc) {
                                goto finished;
+                       }
                        num_rqst++;
                        trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
                        break;
@@ -356,14 +354,13 @@ replay_again:
                                                        COMPOUND_FID, current->tgid,
                                                        FILE_BASIC_INFORMATION,
                                                        SMB2_O_INFO_FILE, 0, data, size);
-                               if (!rc) {
-                                       smb2_set_next_command(tcon, &rqst[num_rqst]);
-                                       smb2_set_related(&rqst[num_rqst]);
-                               }
                        }
-
-                       if (rc)
+                       if (!rc && (!cfile || num_rqst > 1)) {
+                               smb2_set_next_command(tcon, &rqst[num_rqst]);
+                               smb2_set_related(&rqst[num_rqst]);
+                       } else if (rc) {
                                goto finished;
+                       }
                        num_rqst++;
                        trace_smb3_set_info_compound_enter(xid, ses->Suid,
                                                           tcon->tid, full_path);
@@ -397,13 +394,13 @@ replay_again:
                                                        COMPOUND_FID, COMPOUND_FID,
                                                        current->tgid, FILE_RENAME_INFORMATION,
                                                        SMB2_O_INFO_FILE, 0, data, size);
-                               if (!rc) {
-                                       smb2_set_next_command(tcon, &rqst[num_rqst]);
-                                       smb2_set_related(&rqst[num_rqst]);
-                               }
                        }
-                       if (rc)
+                       if (!rc && (!cfile || num_rqst > 1)) {
+                               smb2_set_next_command(tcon, &rqst[num_rqst]);
+                               smb2_set_related(&rqst[num_rqst]);
+                       } else if (rc) {
                                goto finished;
+                       }
                        num_rqst++;
                        trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
                        break;
@@ -438,15 +435,27 @@ replay_again:
                        rqst[num_rqst].rq_iov = vars->io_iov;
                        rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
 
-                       rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
-                                            COMPOUND_FID, COMPOUND_FID,
-                                            FSCTL_SET_REPARSE_POINT,
-                                            in_iov[i].iov_base,
-                                            in_iov[i].iov_len, 0);
-                       if (rc)
+                       if (cfile) {
+                               rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
+                                                    cfile->fid.persistent_fid,
+                                                    cfile->fid.volatile_fid,
+                                                    FSCTL_SET_REPARSE_POINT,
+                                                    in_iov[i].iov_base,
+                                                    in_iov[i].iov_len, 0);
+                       } else {
+                               rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
+                                                    COMPOUND_FID, COMPOUND_FID,
+                                                    FSCTL_SET_REPARSE_POINT,
+                                                    in_iov[i].iov_base,
+                                                    in_iov[i].iov_len, 0);
+                       }
+                       if (!rc && (!cfile || num_rqst > 1)) {
+                               smb2_set_next_command(tcon, &rqst[num_rqst]);
+                               smb2_set_related(&rqst[num_rqst]);
+                       } else if (rc) {
                                goto finished;
-                       smb2_set_next_command(tcon, &rqst[num_rqst]);
-                       smb2_set_related(&rqst[num_rqst++]);
+                       }
+                       num_rqst++;
                        trace_smb3_set_reparse_compound_enter(xid, ses->Suid,
                                                              tcon->tid, full_path);
                        break;
@@ -454,14 +463,25 @@ replay_again:
                        rqst[num_rqst].rq_iov = vars->io_iov;
                        rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
 
-                       rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
-                                            COMPOUND_FID, COMPOUND_FID,
-                                            FSCTL_GET_REPARSE_POINT,
-                                            NULL, 0, CIFSMaxBufSize);
-                       if (rc)
+                       if (cfile) {
+                               rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
+                                                    cfile->fid.persistent_fid,
+                                                    cfile->fid.volatile_fid,
+                                                    FSCTL_GET_REPARSE_POINT,
+                                                    NULL, 0, CIFSMaxBufSize);
+                       } else {
+                               rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
+                                                    COMPOUND_FID, COMPOUND_FID,
+                                                    FSCTL_GET_REPARSE_POINT,
+                                                    NULL, 0, CIFSMaxBufSize);
+                       }
+                       if (!rc && (!cfile || num_rqst > 1)) {
+                               smb2_set_next_command(tcon, &rqst[num_rqst]);
+                               smb2_set_related(&rqst[num_rqst]);
+                       } else if (rc) {
                                goto finished;
-                       smb2_set_next_command(tcon, &rqst[num_rqst]);
-                       smb2_set_related(&rqst[num_rqst++]);
+                       }
+                       num_rqst++;
                        trace_smb3_get_reparse_compound_enter(xid, ses->Suid,
                                                              tcon->tid, full_path);
                        break;