ksmbd: don't allow O_TRUNC open on read-only share
authorNamjae Jeon <linkinjeon@kernel.org>
Sun, 7 Jan 2024 12:24:07 +0000 (21:24 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 20 Jan 2024 10:51:48 +0000 (11:51 +0100)
commit d592a9158a112d419f341f035d18d02f8d232def upstream.

When file is changed using notepad on read-only share(read_only = yes in
ksmbd.conf), There is a problem where existing data is truncated.
notepad in windows try to O_TRUNC open(FILE_OVERWRITE_IF) and all data
in file is truncated. This patch don't allow  O_TRUNC open on read-only
share and add KSMBD_TREE_CONN_FLAG_WRITABLE check in smb2_set_info().

Cc: stable@vger.kernel.org
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/smb/server/smb2pdu.c

index fbd708b..0e4d514 100644 (file)
@@ -2971,7 +2971,7 @@ int smb2_open(struct ksmbd_work *work)
                                            &may_flags);
 
        if (!test_tree_conn_flag(tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
-               if (open_flags & O_CREAT) {
+               if (open_flags & (O_CREAT | O_TRUNC)) {
                        ksmbd_debug(SMB,
                                    "User does not have write permission\n");
                        rc = -EACCES;
@@ -5943,12 +5943,6 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
        }
        case FILE_RENAME_INFORMATION:
        {
-               if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
-                       ksmbd_debug(SMB,
-                                   "User does not have write permission\n");
-                       return -EACCES;
-               }
-
                if (buf_len < sizeof(struct smb2_file_rename_info))
                        return -EINVAL;
 
@@ -5968,12 +5962,6 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
        }
        case FILE_DISPOSITION_INFORMATION:
        {
-               if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
-                       ksmbd_debug(SMB,
-                                   "User does not have write permission\n");
-                       return -EACCES;
-               }
-
                if (buf_len < sizeof(struct smb2_file_disposition_info))
                        return -EINVAL;
 
@@ -6035,7 +6023,7 @@ int smb2_set_info(struct ksmbd_work *work)
 {
        struct smb2_set_info_req *req;
        struct smb2_set_info_rsp *rsp;
-       struct ksmbd_file *fp;
+       struct ksmbd_file *fp = NULL;
        int rc = 0;
        unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
 
@@ -6055,6 +6043,13 @@ int smb2_set_info(struct ksmbd_work *work)
                rsp = smb2_get_msg(work->response_buf);
        }
 
+       if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
+               ksmbd_debug(SMB, "User does not have write permission\n");
+               pr_err("User does not have write permission\n");
+               rc = -EACCES;
+               goto err_out;
+       }
+
        if (!has_file_id(id)) {
                id = req->VolatileFileId;
                pid = req->PersistentFileId;