Re: [bug report] ksmbd: check invalid FileOffset and BeyondFinalZero in FSCTL_ZERO_DATA

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2023-03-03 23:12 GMT+09:00, Dan Carpenter <error27@xxxxxxxxx>:
> Hello Namjae Jeon,
Hello Dan,

I have sent the patch for this to the list.

Thanks for your report!
>
> The patch b5e5f9dfc915: "ksmbd: check invalid FileOffset and
> BeyondFinalZero in FSCTL_ZERO_DATA" from Jun 19, 2022, leads to the
> following Smatch static checker warning:
>
> 	fs/ksmbd/smb2pdu.c:7759 smb2_ioctl()
> 	warn: no lower bound on 'off'
>
> fs/ksmbd/smb2pdu.c
>     7573 int smb2_ioctl(struct ksmbd_work *work)
>     7574 {
>     7575         struct smb2_ioctl_req *req;
>     7576         struct smb2_ioctl_rsp *rsp;
>     7577         unsigned int cnt_code, nbytes = 0, out_buf_len,
> in_buf_len;
>     7578         u64 id = KSMBD_NO_FID;
>     7579         struct ksmbd_conn *conn = work->conn;
>     7580         int ret = 0;
>     7581
>     7582         if (work->next_smb2_rcv_hdr_off) {
>     7583                 req = ksmbd_req_buf_next(work);
>     7584                 rsp = ksmbd_resp_buf_next(work);
>     7585                 if (!has_file_id(req->VolatileFileId)) {
>     7586                         ksmbd_debug(SMB, "Compound request set FID
> = %llu\n",
>     7587                                     work->compound_fid);
>     7588                         id = work->compound_fid;
>     7589                 }
>     7590         } else {
>     7591                 req = smb2_get_msg(work->request_buf);
>     7592                 rsp = smb2_get_msg(work->response_buf);
>     7593         }
>     7594
>     7595         if (!has_file_id(id))
>     7596                 id = req->VolatileFileId;
>     7597
>     7598         if (req->Flags != cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL)) {
>     7599                 rsp->hdr.Status = STATUS_NOT_SUPPORTED;
>     7600                 goto out;
>     7601         }
>     7602
>     7603         cnt_code = le32_to_cpu(req->CtlCode);
>     7604         ret = smb2_calc_max_out_buf_len(work, 48,
>     7605
> le32_to_cpu(req->MaxOutputResponse));
>     7606         if (ret < 0) {
>     7607                 rsp->hdr.Status = STATUS_INVALID_PARAMETER;
>     7608                 goto out;
>     7609         }
>     7610         out_buf_len = (unsigned int)ret;
>     7611         in_buf_len = le32_to_cpu(req->InputCount);
>     7612
>     7613         switch (cnt_code) {
>     7614         case FSCTL_DFS_GET_REFERRALS:
>     7615         case FSCTL_DFS_GET_REFERRALS_EX:
>     7616                 /* Not support DFS yet */
>     7617                 rsp->hdr.Status = STATUS_FS_DRIVER_REQUIRED;
>     7618                 goto out;
>     7619         case FSCTL_CREATE_OR_GET_OBJECT_ID:
>     7620         {
>     7621                 struct file_object_buf_type1_ioctl_rsp *obj_buf;
>     7622
>     7623                 nbytes = sizeof(struct
> file_object_buf_type1_ioctl_rsp);
>     7624                 obj_buf = (struct file_object_buf_type1_ioctl_rsp
> *)
>     7625                         &rsp->Buffer[0];
>     7626
>     7627                 /*
>     7628                  * TODO: This is dummy implementation to pass
> smbtorture
>     7629                  * Need to check correct response later
>     7630                  */
>     7631                 memset(obj_buf->ObjectId, 0x0, 16);
>     7632                 memset(obj_buf->BirthVolumeId, 0x0, 16);
>     7633                 memset(obj_buf->BirthObjectId, 0x0, 16);
>     7634                 memset(obj_buf->DomainId, 0x0, 16);
>     7635
>     7636                 break;
>     7637         }
>     7638         case FSCTL_PIPE_TRANSCEIVE:
>     7639                 out_buf_len = min_t(u32, KSMBD_IPC_MAX_PAYLOAD,
> out_buf_len);
>     7640                 nbytes = fsctl_pipe_transceive(work, id,
> out_buf_len, req, rsp);
>     7641                 break;
>     7642         case FSCTL_VALIDATE_NEGOTIATE_INFO:
>     7643                 if (conn->dialect < SMB30_PROT_ID) {
>     7644                         ret = -EOPNOTSUPP;
>     7645                         goto out;
>     7646                 }
>     7647
>     7648                 if (in_buf_len < offsetof(struct
> validate_negotiate_info_req,
>     7649                                           Dialects)) {
>     7650                         ret = -EINVAL;
>     7651                         goto out;
>     7652                 }
>     7653
>     7654                 if (out_buf_len < sizeof(struct
> validate_negotiate_info_rsp)) {
>     7655                         ret = -EINVAL;
>     7656                         goto out;
>     7657                 }
>     7658
>     7659                 ret = fsctl_validate_negotiate_info(conn,
>     7660                         (struct validate_negotiate_info_req
> *)&req->Buffer[0],
>     7661                         (struct validate_negotiate_info_rsp
> *)&rsp->Buffer[0],
>     7662                         in_buf_len);
>     7663                 if (ret < 0)
>     7664                         goto out;
>     7665
>     7666                 nbytes = sizeof(struct
> validate_negotiate_info_rsp);
>     7667                 rsp->PersistentFileId = SMB2_NO_FID;
>     7668                 rsp->VolatileFileId = SMB2_NO_FID;
>     7669                 break;
>     7670         case FSCTL_QUERY_NETWORK_INTERFACE_INFO:
>     7671                 ret = fsctl_query_iface_info_ioctl(conn, rsp,
> out_buf_len);
>     7672                 if (ret < 0)
>     7673                         goto out;
>     7674                 nbytes = ret;
>     7675                 break;
>     7676         case FSCTL_REQUEST_RESUME_KEY:
>     7677                 if (out_buf_len < sizeof(struct
> resume_key_ioctl_rsp)) {
>     7678                         ret = -EINVAL;
>     7679                         goto out;
>     7680                 }
>     7681
>     7682                 ret = fsctl_request_resume_key(work, req,
>     7683                                                (struct
> resume_key_ioctl_rsp *)&rsp->Buffer[0]);
>     7684                 if (ret < 0)
>     7685                         goto out;
>     7686                 rsp->PersistentFileId = req->PersistentFileId;
>     7687                 rsp->VolatileFileId = req->VolatileFileId;
>     7688                 nbytes = sizeof(struct resume_key_ioctl_rsp);
>     7689                 break;
>     7690         case FSCTL_COPYCHUNK:
>     7691         case FSCTL_COPYCHUNK_WRITE:
>     7692                 if (!test_tree_conn_flag(work->tcon,
> KSMBD_TREE_CONN_FLAG_WRITABLE)) {
>     7693                         ksmbd_debug(SMB,
>     7694                                     "User does not have write
> permission\n");
>     7695                         ret = -EACCES;
>     7696                         goto out;
>     7697                 }
>     7698
>     7699                 if (in_buf_len < sizeof(struct
> copychunk_ioctl_req)) {
>     7700                         ret = -EINVAL;
>     7701                         goto out;
>     7702                 }
>     7703
>     7704                 if (out_buf_len < sizeof(struct
> copychunk_ioctl_rsp)) {
>     7705                         ret = -EINVAL;
>     7706                         goto out;
>     7707                 }
>     7708
>     7709                 nbytes = sizeof(struct copychunk_ioctl_rsp);
>     7710                 rsp->VolatileFileId = req->VolatileFileId;
>     7711                 rsp->PersistentFileId = req->PersistentFileId;
>     7712                 fsctl_copychunk(work,
>     7713                                 (struct copychunk_ioctl_req
> *)&req->Buffer[0],
>     7714                                 le32_to_cpu(req->CtlCode),
>     7715                                 le32_to_cpu(req->InputCount),
>     7716                                 req->VolatileFileId,
>     7717                                 req->PersistentFileId,
>     7718                                 rsp);
>     7719                 break;
>     7720         case FSCTL_SET_SPARSE:
>     7721                 if (in_buf_len < sizeof(struct file_sparse)) {
>     7722                         ret = -EINVAL;
>     7723                         goto out;
>     7724                 }
>     7725
>     7726                 ret = fsctl_set_sparse(work, id,
>     7727                                        (struct file_sparse
> *)&req->Buffer[0]);
>     7728                 if (ret < 0)
>     7729                         goto out;
>     7730                 break;
>     7731         case FSCTL_SET_ZERO_DATA:
>     7732         {
>     7733                 struct file_zero_data_information *zero_data;
>     7734                 struct ksmbd_file *fp;
>     7735                 loff_t off, len, bfz;
>     7736
>     7737                 if (!test_tree_conn_flag(work->tcon,
> KSMBD_TREE_CONN_FLAG_WRITABLE)) {
>     7738                         ksmbd_debug(SMB,
>     7739                                     "User does not have write
> permission\n");
>     7740                         ret = -EACCES;
>     7741                         goto out;
>     7742                 }
>     7743
>     7744                 if (in_buf_len < sizeof(struct
> file_zero_data_information)) {
>     7745                         ret = -EINVAL;
>     7746                         goto out;
>     7747                 }
>     7748
>     7749                 zero_data =
>     7750                         (struct file_zero_data_information
> *)&req->Buffer[0];
>     7751
>     7752                 off = le64_to_cpu(zero_data->FileOffset);
>     7753                 bfz = le64_to_cpu(zero_data->BeyondFinalZero);
>     7754                 if (off > bfz) {
>
> Should we check for negative values of "off"?  To be honest,
> Smatch doesn't really trust either off or bfz...
>
>     7755                         ret = -EINVAL;
>     7756                         goto out;
>     7757                 }
>     7758
> --> 7759                 len = bfz - off;
>     7760                 if (len) {
>     7761                         fp = ksmbd_lookup_fd_fast(work, id);
>     7762                         if (!fp) {
>     7763                                 ret = -ENOENT;
>     7764                                 goto out;
>     7765                         }
>     7766
>     7767                         ret = ksmbd_vfs_zero_data(work, fp, off,
> len);
>     7768                         ksmbd_fd_put(work, fp);
>     7769                         if (ret < 0)
>     7770                                 goto out;
>     7771                 }
>     7772                 break;
>     7773         }
>
> regards,
> dan carpenter
>



[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux