Commit 8ae5d298 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '6.6-rc-ksmbd-fixes-part1' of git://git.samba.org/ksmbd

Pull smb server updates from Steve French:

 - fix potential overflows in decoding create and in session setup
   requests

 - cleanup fixes

 - compounding fixes, including one for MacOS compounded read requests

 - session setup error handling fix

 - fix mode bit bug when applying force_directory_mode and
   force_create_mode

 - RDMA (smbdirect) write fix

* tag '6.6-rc-ksmbd-fixes-part1' of git://git.samba.org/ksmbd:
  ksmbd: add missing calling smb2_set_err_rsp() on error
  ksmbd: replace one-element array with flex-array member in struct smb2_ea_info
  ksmbd: fix slub overflow in ksmbd_decode_ntlmssp_auth_blob()
  ksmbd: fix wrong DataOffset validation of create context
  ksmbd: Fix one kernel-doc comment
  ksmbd: reduce descriptor size if remaining bytes is less than request size
  ksmbd: fix `force create mode' and `force directory mode'
  ksmbd: fix wrong interim response on compound
  ksmbd: add support for read compound
  ksmbd: switch to use kmemdup_nul() helper
parents 7e5cd6f6 0e2378ea
...@@ -214,12 +214,10 @@ static int ksmbd_neg_token_alloc(void *context, size_t hdrlen, ...@@ -214,12 +214,10 @@ static int ksmbd_neg_token_alloc(void *context, size_t hdrlen,
{ {
struct ksmbd_conn *conn = context; struct ksmbd_conn *conn = context;
conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL); conn->mechToken = kmemdup_nul(value, vlen, GFP_KERNEL);
if (!conn->mechToken) if (!conn->mechToken)
return -ENOMEM; return -ENOMEM;
memcpy(conn->mechToken, value, vlen);
conn->mechToken[vlen] = '\0';
return 0; return 0;
} }
......
...@@ -355,6 +355,9 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob, ...@@ -355,6 +355,9 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
if (blob_len < (u64)sess_key_off + sess_key_len) if (blob_len < (u64)sess_key_off + sess_key_len)
return -EINVAL; return -EINVAL;
if (sess_key_len > CIFS_KEY_SIZE)
return -EINVAL;
ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL); ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL);
if (!ctx_arc4) if (!ctx_arc4)
return -ENOMEM; return -ENOMEM;
...@@ -1029,11 +1032,15 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec, ...@@ -1029,11 +1032,15 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
{ {
struct scatterlist *sg; struct scatterlist *sg;
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
int i, nr_entries[3] = {0}, total_entries = 0, sg_idx = 0; int i, *nr_entries, total_entries = 0, sg_idx = 0;
if (!nvec) if (!nvec)
return NULL; return NULL;
nr_entries = kcalloc(nvec, sizeof(int), GFP_KERNEL);
if (!nr_entries)
return NULL;
for (i = 0; i < nvec - 1; i++) { for (i = 0; i < nvec - 1; i++) {
unsigned long kaddr = (unsigned long)iov[i + 1].iov_base; unsigned long kaddr = (unsigned long)iov[i + 1].iov_base;
...@@ -1051,8 +1058,10 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec, ...@@ -1051,8 +1058,10 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
total_entries += 2; total_entries += 2;
sg = kmalloc_array(total_entries, sizeof(struct scatterlist), GFP_KERNEL); sg = kmalloc_array(total_entries, sizeof(struct scatterlist), GFP_KERNEL);
if (!sg) if (!sg) {
kfree(nr_entries);
return NULL; return NULL;
}
sg_init_table(sg, total_entries); sg_init_table(sg, total_entries);
smb2_sg_set_buf(&sg[sg_idx++], iov[0].iov_base + 24, assoc_data_len); smb2_sg_set_buf(&sg[sg_idx++], iov[0].iov_base + 24, assoc_data_len);
...@@ -1086,6 +1095,7 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec, ...@@ -1086,6 +1095,7 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
} }
} }
smb2_sg_set_buf(&sg[sg_idx], sign, SMB2_SIGNATURE_SIZE); smb2_sg_set_buf(&sg[sg_idx], sign, SMB2_SIGNATURE_SIZE);
kfree(nr_entries);
return sg; return sg;
} }
......
...@@ -123,28 +123,22 @@ void ksmbd_conn_enqueue_request(struct ksmbd_work *work) ...@@ -123,28 +123,22 @@ void ksmbd_conn_enqueue_request(struct ksmbd_work *work)
} }
} }
int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work) void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
{ {
struct ksmbd_conn *conn = work->conn; struct ksmbd_conn *conn = work->conn;
int ret = 1;
if (list_empty(&work->request_entry) && if (list_empty(&work->request_entry) &&
list_empty(&work->async_request_entry)) list_empty(&work->async_request_entry))
return 0; return;
if (!work->multiRsp)
atomic_dec(&conn->req_running); atomic_dec(&conn->req_running);
if (!work->multiRsp) {
spin_lock(&conn->request_lock); spin_lock(&conn->request_lock);
list_del_init(&work->request_entry); list_del_init(&work->request_entry);
spin_unlock(&conn->request_lock); spin_unlock(&conn->request_lock);
if (work->asynchronous) if (work->asynchronous)
release_async_work(work); release_async_work(work);
ret = 0;
}
wake_up_all(&conn->req_running_q); wake_up_all(&conn->req_running_q);
return ret;
} }
void ksmbd_conn_lock(struct ksmbd_conn *conn) void ksmbd_conn_lock(struct ksmbd_conn *conn)
...@@ -193,39 +187,20 @@ void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id) ...@@ -193,39 +187,20 @@ void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id)
int ksmbd_conn_write(struct ksmbd_work *work) int ksmbd_conn_write(struct ksmbd_work *work)
{ {
struct ksmbd_conn *conn = work->conn; struct ksmbd_conn *conn = work->conn;
size_t len = 0;
int sent; int sent;
struct kvec iov[3];
int iov_idx = 0;
if (!work->response_buf) { if (!work->response_buf) {
pr_err("NULL response header\n"); pr_err("NULL response header\n");
return -EINVAL; return -EINVAL;
} }
if (work->tr_buf) { if (work->send_no_response)
iov[iov_idx] = (struct kvec) { work->tr_buf, return 0;
sizeof(struct smb2_transform_hdr) + 4 };
len += iov[iov_idx++].iov_len;
}
if (work->aux_payload_sz) {
iov[iov_idx] = (struct kvec) { work->response_buf, work->resp_hdr_sz };
len += iov[iov_idx++].iov_len;
iov[iov_idx] = (struct kvec) { work->aux_payload_buf, work->aux_payload_sz };
len += iov[iov_idx++].iov_len;
} else {
if (work->tr_buf)
iov[iov_idx].iov_len = work->resp_hdr_sz;
else
iov[iov_idx].iov_len = get_rfc1002_len(work->response_buf) + 4;
iov[iov_idx].iov_base = work->response_buf;
len += iov[iov_idx++].iov_len;
}
ksmbd_conn_lock(conn); ksmbd_conn_lock(conn);
sent = conn->transport->ops->writev(conn->transport, &iov[0], sent = conn->transport->ops->writev(conn->transport, work->iov,
iov_idx, len, work->iov_cnt,
get_rfc1002_len(work->iov[0].iov_base) + 4,
work->need_invalidate_rkey, work->need_invalidate_rkey,
work->remote_key); work->remote_key);
ksmbd_conn_unlock(conn); ksmbd_conn_unlock(conn);
......
...@@ -158,7 +158,7 @@ int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, ...@@ -158,7 +158,7 @@ int ksmbd_conn_rdma_write(struct ksmbd_conn *conn,
struct smb2_buffer_desc_v1 *desc, struct smb2_buffer_desc_v1 *desc,
unsigned int desc_len); unsigned int desc_len);
void ksmbd_conn_enqueue_request(struct ksmbd_work *work); void ksmbd_conn_enqueue_request(struct ksmbd_work *work);
int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work); void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work);
void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops); void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops);
int ksmbd_conn_handler_loop(void *p); int ksmbd_conn_handler_loop(void *p);
int ksmbd_conn_transport_init(void); int ksmbd_conn_transport_init(void);
......
...@@ -27,18 +27,35 @@ struct ksmbd_work *ksmbd_alloc_work_struct(void) ...@@ -27,18 +27,35 @@ struct ksmbd_work *ksmbd_alloc_work_struct(void)
INIT_LIST_HEAD(&work->async_request_entry); INIT_LIST_HEAD(&work->async_request_entry);
INIT_LIST_HEAD(&work->fp_entry); INIT_LIST_HEAD(&work->fp_entry);
INIT_LIST_HEAD(&work->interim_entry); INIT_LIST_HEAD(&work->interim_entry);
INIT_LIST_HEAD(&work->aux_read_list);
work->iov_alloc_cnt = 4;
work->iov = kcalloc(work->iov_alloc_cnt, sizeof(struct kvec),
GFP_KERNEL);
if (!work->iov) {
kmem_cache_free(work_cache, work);
work = NULL;
}
} }
return work; return work;
} }
void ksmbd_free_work_struct(struct ksmbd_work *work) void ksmbd_free_work_struct(struct ksmbd_work *work)
{ {
struct aux_read *ar, *tmp;
WARN_ON(work->saved_cred != NULL); WARN_ON(work->saved_cred != NULL);
kvfree(work->response_buf); kvfree(work->response_buf);
kvfree(work->aux_payload_buf);
list_for_each_entry_safe(ar, tmp, &work->aux_read_list, entry) {
kvfree(ar->buf);
list_del(&ar->entry);
kfree(ar);
}
kfree(work->tr_buf); kfree(work->tr_buf);
kvfree(work->request_buf); kvfree(work->request_buf);
kfree(work->iov);
if (work->async_id) if (work->async_id)
ksmbd_release_id(&work->conn->async_ida, work->async_id); ksmbd_release_id(&work->conn->async_ida, work->async_id);
kmem_cache_free(work_cache, work); kmem_cache_free(work_cache, work);
...@@ -77,3 +94,77 @@ bool ksmbd_queue_work(struct ksmbd_work *work) ...@@ -77,3 +94,77 @@ bool ksmbd_queue_work(struct ksmbd_work *work)
{ {
return queue_work(ksmbd_wq, &work->work); return queue_work(ksmbd_wq, &work->work);
} }
static int ksmbd_realloc_iov_pin(struct ksmbd_work *work, void *ib,
unsigned int ib_len)
{
if (work->iov_alloc_cnt <= work->iov_cnt) {
struct kvec *new;
work->iov_alloc_cnt += 4;
new = krealloc(work->iov,
sizeof(struct kvec) * work->iov_alloc_cnt,
GFP_KERNEL | __GFP_ZERO);
if (!new)
return -ENOMEM;
work->iov = new;
}
work->iov[++work->iov_idx].iov_base = ib;
work->iov[work->iov_idx].iov_len = ib_len;
work->iov_cnt++;
return 0;
}
static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
void *aux_buf, unsigned int aux_size)
{
/* Plus rfc_length size on first iov */
if (!work->iov_idx) {
work->iov[work->iov_idx].iov_base = work->response_buf;
*(__be32 *)work->iov[0].iov_base = 0;
work->iov[work->iov_idx].iov_len = 4;
work->iov_cnt++;
}
ksmbd_realloc_iov_pin(work, ib, len);
inc_rfc1001_len(work->iov[0].iov_base, len);
if (aux_size) {
struct aux_read *ar;
ksmbd_realloc_iov_pin(work, aux_buf, aux_size);
inc_rfc1001_len(work->iov[0].iov_base, aux_size);
ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL);
if (!ar)
return -ENOMEM;
ar->buf = aux_buf;
list_add(&ar->entry, &work->aux_read_list);
}
return 0;
}
int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len)
{
return __ksmbd_iov_pin_rsp(work, ib, len, NULL, 0);
}
int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len,
void *aux_buf, unsigned int aux_size)
{
return __ksmbd_iov_pin_rsp(work, ib, len, aux_buf, aux_size);
}
int allocate_interim_rsp_buf(struct ksmbd_work *work)
{
work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL);
if (!work->response_buf)
return -ENOMEM;
work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
return 0;
}
...@@ -19,6 +19,11 @@ enum { ...@@ -19,6 +19,11 @@ enum {
KSMBD_WORK_CLOSED, KSMBD_WORK_CLOSED,
}; };
struct aux_read {
void *buf;
struct list_head entry;
};
/* one of these for every pending CIFS request at the connection */ /* one of these for every pending CIFS request at the connection */
struct ksmbd_work { struct ksmbd_work {
/* Server corresponding to this mid */ /* Server corresponding to this mid */
...@@ -31,13 +36,19 @@ struct ksmbd_work { ...@@ -31,13 +36,19 @@ struct ksmbd_work {
/* Response buffer */ /* Response buffer */
void *response_buf; void *response_buf;
/* Read data buffer */ struct list_head aux_read_list;
void *aux_payload_buf;
struct kvec *iov;
int iov_alloc_cnt;
int iov_cnt;
int iov_idx;
/* Next cmd hdr in compound req buf*/ /* Next cmd hdr in compound req buf*/
int next_smb2_rcv_hdr_off; int next_smb2_rcv_hdr_off;
/* Next cmd hdr in compound rsp buf*/ /* Next cmd hdr in compound rsp buf*/
int next_smb2_rsp_hdr_off; int next_smb2_rsp_hdr_off;
/* Current cmd hdr in compound rsp buf*/
int curr_smb2_rsp_hdr_off;
/* /*
* Current Local FID assigned compound response if SMB2 CREATE * Current Local FID assigned compound response if SMB2 CREATE
...@@ -53,16 +64,11 @@ struct ksmbd_work { ...@@ -53,16 +64,11 @@ struct ksmbd_work {
unsigned int credits_granted; unsigned int credits_granted;
/* response smb header size */ /* response smb header size */
unsigned int resp_hdr_sz;
unsigned int response_sz; unsigned int response_sz;
/* Read data count */
unsigned int aux_payload_sz;
void *tr_buf; void *tr_buf;
unsigned char state; unsigned char state;
/* Multiple responses for one request e.g. SMB ECHO */
bool multiRsp:1;
/* No response for cancelled request */ /* No response for cancelled request */
bool send_no_response:1; bool send_no_response:1;
/* Request is encrypted */ /* Request is encrypted */
...@@ -95,6 +101,15 @@ static inline void *ksmbd_resp_buf_next(struct ksmbd_work *work) ...@@ -95,6 +101,15 @@ static inline void *ksmbd_resp_buf_next(struct ksmbd_work *work)
return work->response_buf + work->next_smb2_rsp_hdr_off + 4; return work->response_buf + work->next_smb2_rsp_hdr_off + 4;
} }
/**
* ksmbd_resp_buf_curr - Get current buffer on compound response.
* @work: smb work containing response buffer
*/
static inline void *ksmbd_resp_buf_curr(struct ksmbd_work *work)
{
return work->response_buf + work->curr_smb2_rsp_hdr_off + 4;
}
/** /**
* ksmbd_req_buf_next - Get next buffer on compound request. * ksmbd_req_buf_next - Get next buffer on compound request.
* @work: smb work containing response buffer * @work: smb work containing response buffer
...@@ -113,5 +128,8 @@ int ksmbd_work_pool_init(void); ...@@ -113,5 +128,8 @@ int ksmbd_work_pool_init(void);
int ksmbd_workqueue_init(void); int ksmbd_workqueue_init(void);
void ksmbd_workqueue_destroy(void); void ksmbd_workqueue_destroy(void);
bool ksmbd_queue_work(struct ksmbd_work *work); bool ksmbd_queue_work(struct ksmbd_work *work);
int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len,
void *aux_buf, unsigned int aux_size);
int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len);
int allocate_interim_rsp_buf(struct ksmbd_work *work);
#endif /* __KSMBD_WORK_H__ */ #endif /* __KSMBD_WORK_H__ */
...@@ -34,29 +34,22 @@ struct ksmbd_share_config { ...@@ -34,29 +34,22 @@ struct ksmbd_share_config {
#define KSMBD_SHARE_INVALID_UID ((__u16)-1) #define KSMBD_SHARE_INVALID_UID ((__u16)-1)
#define KSMBD_SHARE_INVALID_GID ((__u16)-1) #define KSMBD_SHARE_INVALID_GID ((__u16)-1)
static inline int share_config_create_mode(struct ksmbd_share_config *share, static inline umode_t
share_config_create_mode(struct ksmbd_share_config *share,
umode_t posix_mode) umode_t posix_mode)
{ {
if (!share->force_create_mode) { umode_t mode = (posix_mode ?: (umode_t)-1) & share->create_mask;
if (!posix_mode)
return share->create_mask; return mode | share->force_create_mode;
else
return posix_mode & share->create_mask;
}
return share->force_create_mode & share->create_mask;
} }
static inline int share_config_directory_mode(struct ksmbd_share_config *share, static inline umode_t
share_config_directory_mode(struct ksmbd_share_config *share,
umode_t posix_mode) umode_t posix_mode)
{ {
if (!share->force_directory_mode) { umode_t mode = (posix_mode ?: (umode_t)-1) & share->directory_mask;
if (!posix_mode)
return share->directory_mask;
else
return posix_mode & share->directory_mask;
}
return share->force_directory_mode & share->directory_mask; return mode | share->force_directory_mode;
} }
static inline int test_share_config_flag(struct ksmbd_share_config *share, static inline int test_share_config_flag(struct ksmbd_share_config *share,
......
...@@ -616,15 +616,6 @@ static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level) ...@@ -616,15 +616,6 @@ static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level)
return 0; return 0;
} }
static inline int allocate_oplock_break_buf(struct ksmbd_work *work)
{
work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL);
if (!work->response_buf)
return -ENOMEM;
work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
return 0;
}
/** /**
* __smb2_oplock_break_noti() - send smb2 oplock break cmd from conn * __smb2_oplock_break_noti() - send smb2 oplock break cmd from conn
* to client * to client
...@@ -639,7 +630,6 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) ...@@ -639,7 +630,6 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
{ {
struct smb2_oplock_break *rsp = NULL; struct smb2_oplock_break *rsp = NULL;
struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work); struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work);
struct ksmbd_conn *conn = work->conn;
struct oplock_break_info *br_info = work->request_buf; struct oplock_break_info *br_info = work->request_buf;
struct smb2_hdr *rsp_hdr; struct smb2_hdr *rsp_hdr;
struct ksmbd_file *fp; struct ksmbd_file *fp;
...@@ -648,7 +638,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) ...@@ -648,7 +638,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
if (!fp) if (!fp)
goto out; goto out;
if (allocate_oplock_break_buf(work)) { if (allocate_interim_rsp_buf(work)) {
pr_err("smb2_allocate_rsp_buf failed! "); pr_err("smb2_allocate_rsp_buf failed! ");
ksmbd_fd_put(work, fp); ksmbd_fd_put(work, fp);
goto out; goto out;
...@@ -656,8 +646,6 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) ...@@ -656,8 +646,6 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
rsp_hdr = smb2_get_msg(work->response_buf); rsp_hdr = smb2_get_msg(work->response_buf);
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
*(__be32 *)work->response_buf =
cpu_to_be32(conn->vals->header_size);
rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
rsp_hdr->CreditRequest = cpu_to_le16(0); rsp_hdr->CreditRequest = cpu_to_le16(0);
...@@ -684,13 +672,15 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) ...@@ -684,13 +672,15 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
rsp->PersistentFid = fp->persistent_id; rsp->PersistentFid = fp->persistent_id;
rsp->VolatileFid = fp->volatile_id; rsp->VolatileFid = fp->volatile_id;
inc_rfc1001_len(work->response_buf, 24); ksmbd_fd_put(work, fp);
if (ksmbd_iov_pin_rsp(work, (void *)rsp,
sizeof(struct smb2_oplock_break)))
goto out;
ksmbd_debug(OPLOCK, ksmbd_debug(OPLOCK,
"sending oplock break v_id %llu p_id = %llu lock level = %d\n", "sending oplock break v_id %llu p_id = %llu lock level = %d\n",
rsp->VolatileFid, rsp->PersistentFid, rsp->OplockLevel); rsp->VolatileFid, rsp->PersistentFid, rsp->OplockLevel);
ksmbd_fd_put(work, fp);
ksmbd_conn_write(work); ksmbd_conn_write(work);
out: out:
...@@ -751,18 +741,15 @@ static void __smb2_lease_break_noti(struct work_struct *wk) ...@@ -751,18 +741,15 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
struct smb2_lease_break *rsp = NULL; struct smb2_lease_break *rsp = NULL;
struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work); struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work);
struct lease_break_info *br_info = work->request_buf; struct lease_break_info *br_info = work->request_buf;
struct ksmbd_conn *conn = work->conn;
struct smb2_hdr *rsp_hdr; struct smb2_hdr *rsp_hdr;
if (allocate_oplock_break_buf(work)) { if (allocate_interim_rsp_buf(work)) {
ksmbd_debug(OPLOCK, "smb2_allocate_rsp_buf failed! "); ksmbd_debug(OPLOCK, "smb2_allocate_rsp_buf failed! ");
goto out; goto out;
} }
rsp_hdr = smb2_get_msg(work->response_buf); rsp_hdr = smb2_get_msg(work->response_buf);
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
*(__be32 *)work->response_buf =
cpu_to_be32(conn->vals->header_size);
rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
rsp_hdr->CreditRequest = cpu_to_le16(0); rsp_hdr->CreditRequest = cpu_to_le16(0);
...@@ -791,7 +778,9 @@ static void __smb2_lease_break_noti(struct work_struct *wk) ...@@ -791,7 +778,9 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
rsp->AccessMaskHint = 0; rsp->AccessMaskHint = 0;
rsp->ShareMaskHint = 0; rsp->ShareMaskHint = 0;
inc_rfc1001_len(work->response_buf, 44); if (ksmbd_iov_pin_rsp(work, (void *)rsp,
sizeof(struct smb2_lease_break)))
goto out;
ksmbd_conn_write(work); ksmbd_conn_write(work);
...@@ -1492,7 +1481,7 @@ struct create_context *smb2_find_context_vals(void *open_req, const char *tag, i ...@@ -1492,7 +1481,7 @@ struct create_context *smb2_find_context_vals(void *open_req, const char *tag, i
name_len < 4 || name_len < 4 ||
name_off + name_len > cc_len || name_off + name_len > cc_len ||
(value_off & 0x7) != 0 || (value_off & 0x7) != 0 ||
(value_off && (value_off < name_off + name_len)) || (value_len && value_off < name_off + (name_len < 8 ? 8 : name_len)) ||
((u64)value_off + value_len > cc_len)) ((u64)value_off + value_len > cc_len))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
......
...@@ -163,6 +163,7 @@ static void __handle_ksmbd_work(struct ksmbd_work *work, ...@@ -163,6 +163,7 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
{ {
u16 command = 0; u16 command = 0;
int rc; int rc;
bool is_chained = false;
if (conn->ops->allocate_rsp_buf(work)) if (conn->ops->allocate_rsp_buf(work))
return; return;
...@@ -229,14 +230,13 @@ static void __handle_ksmbd_work(struct ksmbd_work *work, ...@@ -229,14 +230,13 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
} }
} }
is_chained = is_chained_smb2_message(work);
if (work->sess && if (work->sess &&
(work->sess->sign || smb3_11_final_sess_setup_resp(work) || (work->sess->sign || smb3_11_final_sess_setup_resp(work) ||
conn->ops->is_sign_req(work, command))) conn->ops->is_sign_req(work, command)))
conn->ops->set_sign_rsp(work); conn->ops->set_sign_rsp(work);
} while (is_chained_smb2_message(work)); } while (is_chained == true);
if (work->send_no_response)
return;
send: send:
smb3_preauth_hash_rsp(work); smb3_preauth_hash_rsp(work);
......
...@@ -145,12 +145,18 @@ void smb2_set_err_rsp(struct ksmbd_work *work) ...@@ -145,12 +145,18 @@ void smb2_set_err_rsp(struct ksmbd_work *work)
err_rsp = smb2_get_msg(work->response_buf); err_rsp = smb2_get_msg(work->response_buf);
if (err_rsp->hdr.Status != STATUS_STOPPED_ON_SYMLINK) { if (err_rsp->hdr.Status != STATUS_STOPPED_ON_SYMLINK) {
int err;
err_rsp->StructureSize = SMB2_ERROR_STRUCTURE_SIZE2_LE; err_rsp->StructureSize = SMB2_ERROR_STRUCTURE_SIZE2_LE;
err_rsp->ErrorContextCount = 0; err_rsp->ErrorContextCount = 0;
err_rsp->Reserved = 0; err_rsp->Reserved = 0;
err_rsp->ByteCount = 0; err_rsp->ByteCount = 0;
err_rsp->ErrorData[0] = 0; err_rsp->ErrorData[0] = 0;
inc_rfc1001_len(work->response_buf, SMB2_ERROR_STRUCTURE_SIZE2); err = ksmbd_iov_pin_rsp(work, (void *)err_rsp,
__SMB2_HEADER_STRUCTURE_SIZE +
SMB2_ERROR_STRUCTURE_SIZE2);
if (err)
work->send_no_response = 1;
} }
} }
...@@ -245,9 +251,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work) ...@@ -245,9 +251,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
struct smb2_hdr *rsp_hdr; struct smb2_hdr *rsp_hdr;
struct smb2_negotiate_rsp *rsp; struct smb2_negotiate_rsp *rsp;
struct ksmbd_conn *conn = work->conn; struct ksmbd_conn *conn = work->conn;
int err;
*(__be32 *)work->response_buf =
cpu_to_be32(conn->vals->header_size);
rsp_hdr = smb2_get_msg(work->response_buf); rsp_hdr = smb2_get_msg(work->response_buf);
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
...@@ -286,12 +290,13 @@ int init_smb2_neg_rsp(struct ksmbd_work *work) ...@@ -286,12 +290,13 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH); rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH);
ksmbd_copy_gss_neg_header((char *)(&rsp->hdr) + ksmbd_copy_gss_neg_header((char *)(&rsp->hdr) +
le16_to_cpu(rsp->SecurityBufferOffset)); le16_to_cpu(rsp->SecurityBufferOffset));
inc_rfc1001_len(work->response_buf,
sizeof(struct smb2_negotiate_rsp) -
sizeof(struct smb2_hdr) + AUTH_GSS_LENGTH);
rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE; rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE;
if (server_conf.signing == KSMBD_CONFIG_OPT_MANDATORY) if (server_conf.signing == KSMBD_CONFIG_OPT_MANDATORY)
rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE; rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE;
err = ksmbd_iov_pin_rsp(work, rsp,
sizeof(struct smb2_negotiate_rsp) + AUTH_GSS_LENGTH);
if (err)
return err;
conn->use_spnego = true; conn->use_spnego = true;
ksmbd_conn_set_need_negotiate(conn); ksmbd_conn_set_need_negotiate(conn);
...@@ -390,11 +395,12 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work) ...@@ -390,11 +395,12 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work)
next_hdr_offset = le32_to_cpu(req->NextCommand); next_hdr_offset = le32_to_cpu(req->NextCommand);
new_len = ALIGN(len, 8); new_len = ALIGN(len, 8);
inc_rfc1001_len(work->response_buf, work->iov[work->iov_idx].iov_len += (new_len - len);
sizeof(struct smb2_hdr) + new_len - len); inc_rfc1001_len(work->response_buf, new_len - len);
rsp->NextCommand = cpu_to_le32(new_len); rsp->NextCommand = cpu_to_le32(new_len);
work->next_smb2_rcv_hdr_off += next_hdr_offset; work->next_smb2_rcv_hdr_off += next_hdr_offset;
work->curr_smb2_rsp_hdr_off = work->next_smb2_rsp_hdr_off;
work->next_smb2_rsp_hdr_off += new_len; work->next_smb2_rsp_hdr_off += new_len;
ksmbd_debug(SMB, ksmbd_debug(SMB,
"Compound req new_len = %d rcv off = %d rsp off = %d\n", "Compound req new_len = %d rcv off = %d rsp off = %d\n",
...@@ -470,10 +476,10 @@ bool is_chained_smb2_message(struct ksmbd_work *work) ...@@ -470,10 +476,10 @@ bool is_chained_smb2_message(struct ksmbd_work *work)
len = len - get_rfc1002_len(work->response_buf); len = len - get_rfc1002_len(work->response_buf);
if (len) { if (len) {
ksmbd_debug(SMB, "padding len %u\n", len); ksmbd_debug(SMB, "padding len %u\n", len);
work->iov[work->iov_idx].iov_len += len;
inc_rfc1001_len(work->response_buf, len); inc_rfc1001_len(work->response_buf, len);
if (work->aux_payload_sz)
work->aux_payload_sz += len;
} }
work->curr_smb2_rsp_hdr_off = work->next_smb2_rsp_hdr_off;
} }
return false; return false;
} }
...@@ -488,11 +494,8 @@ int init_smb2_rsp_hdr(struct ksmbd_work *work) ...@@ -488,11 +494,8 @@ int init_smb2_rsp_hdr(struct ksmbd_work *work)
{ {
struct smb2_hdr *rsp_hdr = smb2_get_msg(work->response_buf); struct smb2_hdr *rsp_hdr = smb2_get_msg(work->response_buf);
struct smb2_hdr *rcv_hdr = smb2_get_msg(work->request_buf); struct smb2_hdr *rcv_hdr = smb2_get_msg(work->request_buf);
struct ksmbd_conn *conn = work->conn;
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
*(__be32 *)work->response_buf =
cpu_to_be32(conn->vals->header_size);
rsp_hdr->ProtocolId = rcv_hdr->ProtocolId; rsp_hdr->ProtocolId = rcv_hdr->ProtocolId;
rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
rsp_hdr->Command = rcv_hdr->Command; rsp_hdr->Command = rcv_hdr->Command;
...@@ -657,7 +660,7 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg) ...@@ -657,7 +660,7 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
struct ksmbd_conn *conn = work->conn; struct ksmbd_conn *conn = work->conn;
int id; int id;
rsp_hdr = smb2_get_msg(work->response_buf); rsp_hdr = ksmbd_resp_buf_next(work);
rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND; rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;
id = ksmbd_acquire_async_msg_id(&conn->async_ida); id = ksmbd_acquire_async_msg_id(&conn->async_ida);
...@@ -706,15 +709,24 @@ void release_async_work(struct ksmbd_work *work) ...@@ -706,15 +709,24 @@ void release_async_work(struct ksmbd_work *work)
void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status) void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status)
{ {
struct smb2_hdr *rsp_hdr; struct smb2_hdr *rsp_hdr;
struct ksmbd_work *in_work = ksmbd_alloc_work_struct();
rsp_hdr = smb2_get_msg(work->response_buf); if (allocate_interim_rsp_buf(in_work)) {
smb2_set_err_rsp(work); pr_err("smb_allocate_rsp_buf failed!\n");
ksmbd_free_work_struct(in_work);
return;
}
in_work->conn = work->conn;
memcpy(smb2_get_msg(in_work->response_buf), ksmbd_resp_buf_next(work),
__SMB2_HEADER_STRUCTURE_SIZE);
rsp_hdr = smb2_get_msg(in_work->response_buf);
smb2_set_err_rsp(in_work);
rsp_hdr->Status = status; rsp_hdr->Status = status;
work->multiRsp = 1; ksmbd_conn_write(in_work);
ksmbd_conn_write(work); ksmbd_free_work_struct(in_work);
rsp_hdr->Status = 0;
work->multiRsp = 0;
} }
static __le32 smb2_get_reparse_tag_special_file(umode_t mode) static __le32 smb2_get_reparse_tag_special_file(umode_t mode)
...@@ -821,9 +833,8 @@ static void build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt) ...@@ -821,9 +833,8 @@ static void build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt)
pneg_ctxt->Name[15] = 0x7C; pneg_ctxt->Name[15] = 0x7C;
} }
static void assemble_neg_contexts(struct ksmbd_conn *conn, static unsigned int assemble_neg_contexts(struct ksmbd_conn *conn,
struct smb2_negotiate_rsp *rsp, struct smb2_negotiate_rsp *rsp)
void *smb2_buf_len)
{ {
char * const pneg_ctxt = (char *)rsp + char * const pneg_ctxt = (char *)rsp +
le32_to_cpu(rsp->NegotiateContextOffset); le32_to_cpu(rsp->NegotiateContextOffset);
...@@ -834,7 +845,6 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn, ...@@ -834,7 +845,6 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn,
"assemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n"); "assemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n");
build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt, build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt,
conn->preauth_info->Preauth_HashId); conn->preauth_info->Preauth_HashId);
inc_rfc1001_len(smb2_buf_len, AUTH_GSS_PADDING);
ctxt_size = sizeof(struct smb2_preauth_neg_context); ctxt_size = sizeof(struct smb2_preauth_neg_context);
if (conn->cipher_type) { if (conn->cipher_type) {
...@@ -874,7 +884,7 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn, ...@@ -874,7 +884,7 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn,
} }
rsp->NegotiateContextCount = cpu_to_le16(neg_ctxt_cnt); rsp->NegotiateContextCount = cpu_to_le16(neg_ctxt_cnt);
inc_rfc1001_len(smb2_buf_len, ctxt_size); return ctxt_size + AUTH_GSS_PADDING;
} }
static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn, static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn,
...@@ -1090,7 +1100,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) ...@@ -1090,7 +1100,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
struct smb2_negotiate_req *req = smb2_get_msg(work->request_buf); struct smb2_negotiate_req *req = smb2_get_msg(work->request_buf);
struct smb2_negotiate_rsp *rsp = smb2_get_msg(work->response_buf); struct smb2_negotiate_rsp *rsp = smb2_get_msg(work->response_buf);
int rc = 0; int rc = 0;
unsigned int smb2_buf_len, smb2_neg_size; unsigned int smb2_buf_len, smb2_neg_size, neg_ctxt_len = 0;
__le32 status; __le32 status;
ksmbd_debug(SMB, "Received negotiate request\n"); ksmbd_debug(SMB, "Received negotiate request\n");
...@@ -1183,7 +1193,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) ...@@ -1183,7 +1193,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
conn->preauth_info->Preauth_HashValue); conn->preauth_info->Preauth_HashValue);
rsp->NegotiateContextOffset = rsp->NegotiateContextOffset =
cpu_to_le32(OFFSET_OF_NEG_CONTEXT); cpu_to_le32(OFFSET_OF_NEG_CONTEXT);
assemble_neg_contexts(conn, rsp, work->response_buf); neg_ctxt_len = assemble_neg_contexts(conn, rsp);
break; break;
case SMB302_PROT_ID: case SMB302_PROT_ID:
init_smb3_02_server(conn); init_smb3_02_server(conn);
...@@ -1233,8 +1243,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) ...@@ -1233,8 +1243,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH); rsp->SecurityBufferLength = cpu_to_le16(AUTH_GSS_LENGTH);
ksmbd_copy_gss_neg_header((char *)(&rsp->hdr) + ksmbd_copy_gss_neg_header((char *)(&rsp->hdr) +
le16_to_cpu(rsp->SecurityBufferOffset)); le16_to_cpu(rsp->SecurityBufferOffset));
inc_rfc1001_len(work->response_buf, sizeof(struct smb2_negotiate_rsp) -
sizeof(struct smb2_hdr) + AUTH_GSS_LENGTH);
rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE; rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE;
conn->use_spnego = true; conn->use_spnego = true;
...@@ -1252,9 +1261,15 @@ int smb2_handle_negotiate(struct ksmbd_work *work) ...@@ -1252,9 +1261,15 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
ksmbd_conn_set_need_negotiate(conn); ksmbd_conn_set_need_negotiate(conn);
err_out: err_out:
if (rc)
rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
if (!rc)
rc = ksmbd_iov_pin_rsp(work, rsp,
sizeof(struct smb2_negotiate_rsp) +
AUTH_GSS_LENGTH + neg_ctxt_len);
if (rc < 0) if (rc < 0)
smb2_set_err_rsp(work); smb2_set_err_rsp(work);
return rc; return rc;
} }
...@@ -1454,7 +1469,6 @@ static int ntlm_authenticate(struct ksmbd_work *work, ...@@ -1454,7 +1469,6 @@ static int ntlm_authenticate(struct ksmbd_work *work,
memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len); memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len); rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
kfree(spnego_blob); kfree(spnego_blob);
inc_rfc1001_len(work->response_buf, spnego_blob_len - 1);
} }
user = session_user(conn, req); user = session_user(conn, req);
...@@ -1600,7 +1614,6 @@ static int krb5_authenticate(struct ksmbd_work *work, ...@@ -1600,7 +1614,6 @@ static int krb5_authenticate(struct ksmbd_work *work,
return -EINVAL; return -EINVAL;
} }
rsp->SecurityBufferLength = cpu_to_le16(out_len); rsp->SecurityBufferLength = cpu_to_le16(out_len);
inc_rfc1001_len(work->response_buf, out_len - 1);
if ((conn->sign || server_conf.enforced_signing) || if ((conn->sign || server_conf.enforced_signing) ||
(req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED)) (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED))
...@@ -1672,7 +1685,6 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1672,7 +1685,6 @@ int smb2_sess_setup(struct ksmbd_work *work)
rsp->SessionFlags = 0; rsp->SessionFlags = 0;
rsp->SecurityBufferOffset = cpu_to_le16(72); rsp->SecurityBufferOffset = cpu_to_le16(72);
rsp->SecurityBufferLength = 0; rsp->SecurityBufferLength = 0;
inc_rfc1001_len(work->response_buf, 9);
ksmbd_conn_lock(conn); ksmbd_conn_lock(conn);
if (!req->hdr.SessionId) { if (!req->hdr.SessionId) {
...@@ -1808,13 +1820,6 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1808,13 +1820,6 @@ int smb2_sess_setup(struct ksmbd_work *work)
goto out_err; goto out_err;
rsp->hdr.Status = rsp->hdr.Status =
STATUS_MORE_PROCESSING_REQUIRED; STATUS_MORE_PROCESSING_REQUIRED;
/*
* Note: here total size -1 is done as an
* adjustment for 0 size blob
*/
inc_rfc1001_len(work->response_buf,
le16_to_cpu(rsp->SecurityBufferLength) - 1);
} else if (negblob->MessageType == NtLmAuthenticate) { } else if (negblob->MessageType == NtLmAuthenticate) {
rc = ntlm_authenticate(work, req, rsp); rc = ntlm_authenticate(work, req, rsp);
if (rc) if (rc)
...@@ -1899,6 +1904,18 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1899,6 +1904,18 @@ int smb2_sess_setup(struct ksmbd_work *work)
ksmbd_conn_set_need_negotiate(conn); ksmbd_conn_set_need_negotiate(conn);
} }
} }
smb2_set_err_rsp(work);
} else {
unsigned int iov_len;
if (rsp->SecurityBufferLength)
iov_len = offsetof(struct smb2_sess_setup_rsp, Buffer) +
le16_to_cpu(rsp->SecurityBufferLength);
else
iov_len = sizeof(struct smb2_sess_setup_rsp);
rc = ksmbd_iov_pin_rsp(work, rsp, iov_len);
if (rc)
rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
} }
ksmbd_conn_unlock(conn); ksmbd_conn_unlock(conn);
...@@ -1977,13 +1994,16 @@ int smb2_tree_connect(struct ksmbd_work *work) ...@@ -1977,13 +1994,16 @@ int smb2_tree_connect(struct ksmbd_work *work)
status.tree_conn->posix_extensions = true; status.tree_conn->posix_extensions = true;
rsp->StructureSize = cpu_to_le16(16); rsp->StructureSize = cpu_to_le16(16);
inc_rfc1001_len(work->response_buf, 16);
out_err1: out_err1:
rsp->Capabilities = 0; rsp->Capabilities = 0;
rsp->Reserved = 0; rsp->Reserved = 0;
/* default manual caching */ /* default manual caching */
rsp->ShareFlags = SMB2_SHAREFLAG_MANUAL_CACHING; rsp->ShareFlags = SMB2_SHAREFLAG_MANUAL_CACHING;
rc = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_tree_connect_rsp));
if (rc)
status.ret = KSMBD_TREE_CONN_STATUS_NOMEM;
if (!IS_ERR(treename)) if (!IS_ERR(treename))
kfree(treename); kfree(treename);
if (!IS_ERR(name)) if (!IS_ERR(name))
...@@ -2096,20 +2116,27 @@ int smb2_tree_disconnect(struct ksmbd_work *work) ...@@ -2096,20 +2116,27 @@ int smb2_tree_disconnect(struct ksmbd_work *work)
struct smb2_tree_disconnect_req *req; struct smb2_tree_disconnect_req *req;
struct ksmbd_session *sess = work->sess; struct ksmbd_session *sess = work->sess;
struct ksmbd_tree_connect *tcon = work->tcon; struct ksmbd_tree_connect *tcon = work->tcon;
int err;
WORK_BUFFERS(work, req, rsp); WORK_BUFFERS(work, req, rsp);
rsp->StructureSize = cpu_to_le16(4);
inc_rfc1001_len(work->response_buf, 4);
ksmbd_debug(SMB, "request\n"); ksmbd_debug(SMB, "request\n");
rsp->StructureSize = cpu_to_le16(4);
err = ksmbd_iov_pin_rsp(work, rsp,
sizeof(struct smb2_tree_disconnect_rsp));
if (err) {
rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
smb2_set_err_rsp(work);
return err;
}
if (!tcon || test_and_set_bit(TREE_CONN_EXPIRE, &tcon->status)) { if (!tcon || test_and_set_bit(TREE_CONN_EXPIRE, &tcon->status)) {
ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
smb2_set_err_rsp(work); smb2_set_err_rsp(work);
return 0; return -ENOENT;
} }
ksmbd_close_tree_conn_fds(work); ksmbd_close_tree_conn_fds(work);
...@@ -2131,15 +2158,21 @@ int smb2_session_logoff(struct ksmbd_work *work) ...@@ -2131,15 +2158,21 @@ int smb2_session_logoff(struct ksmbd_work *work)
struct smb2_logoff_rsp *rsp; struct smb2_logoff_rsp *rsp;
struct ksmbd_session *sess; struct ksmbd_session *sess;
u64 sess_id; u64 sess_id;
int err;
WORK_BUFFERS(work, req, rsp); WORK_BUFFERS(work, req, rsp);
ksmbd_debug(SMB, "request\n");
sess_id = le64_to_cpu(req->hdr.SessionId); sess_id = le64_to_cpu(req->hdr.SessionId);
rsp->StructureSize = cpu_to_le16(4); rsp->StructureSize = cpu_to_le16(4);
inc_rfc1001_len(work->response_buf, 4); err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp));
if (err) {
ksmbd_debug(SMB, "request\n"); rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
smb2_set_err_rsp(work);
return err;
}
ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT); ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT);
ksmbd_close_session_fds(work); ksmbd_close_session_fds(work);
...@@ -2154,7 +2187,7 @@ int smb2_session_logoff(struct ksmbd_work *work) ...@@ -2154,7 +2187,7 @@ int smb2_session_logoff(struct ksmbd_work *work)
ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
smb2_set_err_rsp(work); smb2_set_err_rsp(work);
return 0; return -ENOENT;
} }
ksmbd_destroy_file_table(&sess->file_table); ksmbd_destroy_file_table(&sess->file_table);
...@@ -2215,7 +2248,10 @@ static noinline int create_smb2_pipe(struct ksmbd_work *work) ...@@ -2215,7 +2248,10 @@ static noinline int create_smb2_pipe(struct ksmbd_work *work)
rsp->CreateContextsOffset = 0; rsp->CreateContextsOffset = 0;
rsp->CreateContextsLength = 0; rsp->CreateContextsLength = 0;
inc_rfc1001_len(work->response_buf, 88); /* StructureSize - 1*/ err = ksmbd_iov_pin_rsp(work, rsp, offsetof(struct smb2_create_rsp, Buffer));
if (err)
goto out;
kfree(name); kfree(name);
return 0; return 0;
...@@ -2597,6 +2633,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2597,6 +2633,7 @@ int smb2_open(struct ksmbd_work *work)
u64 time; u64 time;
umode_t posix_mode = 0; umode_t posix_mode = 0;
__le32 daccess, maximal_access = 0; __le32 daccess, maximal_access = 0;
int iov_len = 0;
WORK_BUFFERS(work, req, rsp); WORK_BUFFERS(work, req, rsp);
...@@ -3248,7 +3285,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3248,7 +3285,7 @@ int smb2_open(struct ksmbd_work *work)
rsp->CreateContextsOffset = 0; rsp->CreateContextsOffset = 0;
rsp->CreateContextsLength = 0; rsp->CreateContextsLength = 0;
inc_rfc1001_len(work->response_buf, 88); /* StructureSize - 1*/ iov_len = offsetof(struct smb2_create_rsp, Buffer);
/* If lease is request send lease context response */ /* If lease is request send lease context response */
if (opinfo && opinfo->is_lease) { if (opinfo && opinfo->is_lease) {
...@@ -3263,8 +3300,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3263,8 +3300,7 @@ int smb2_open(struct ksmbd_work *work)
create_lease_buf(rsp->Buffer, opinfo->o_lease); create_lease_buf(rsp->Buffer, opinfo->o_lease);
le32_add_cpu(&rsp->CreateContextsLength, le32_add_cpu(&rsp->CreateContextsLength,
conn->vals->create_lease_size); conn->vals->create_lease_size);
inc_rfc1001_len(work->response_buf, iov_len += conn->vals->create_lease_size;
conn->vals->create_lease_size);
next_ptr = &lease_ccontext->Next; next_ptr = &lease_ccontext->Next;
next_off = conn->vals->create_lease_size; next_off = conn->vals->create_lease_size;
} }
...@@ -3284,8 +3320,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3284,8 +3320,7 @@ int smb2_open(struct ksmbd_work *work)
le32_to_cpu(maximal_access)); le32_to_cpu(maximal_access));
le32_add_cpu(&rsp->CreateContextsLength, le32_add_cpu(&rsp->CreateContextsLength,
conn->vals->create_mxac_size); conn->vals->create_mxac_size);
inc_rfc1001_len(work->response_buf, iov_len += conn->vals->create_mxac_size;
conn->vals->create_mxac_size);
if (next_ptr) if (next_ptr)
*next_ptr = cpu_to_le32(next_off); *next_ptr = cpu_to_le32(next_off);
next_ptr = &mxac_ccontext->Next; next_ptr = &mxac_ccontext->Next;
...@@ -3303,8 +3338,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3303,8 +3338,7 @@ int smb2_open(struct ksmbd_work *work)
stat.ino, tcon->id); stat.ino, tcon->id);
le32_add_cpu(&rsp->CreateContextsLength, le32_add_cpu(&rsp->CreateContextsLength,
conn->vals->create_disk_id_size); conn->vals->create_disk_id_size);
inc_rfc1001_len(work->response_buf, iov_len += conn->vals->create_disk_id_size;
conn->vals->create_disk_id_size);
if (next_ptr) if (next_ptr)
*next_ptr = cpu_to_le32(next_off); *next_ptr = cpu_to_le32(next_off);
next_ptr = &disk_id_ccontext->Next; next_ptr = &disk_id_ccontext->Next;
...@@ -3318,8 +3352,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3318,8 +3352,7 @@ int smb2_open(struct ksmbd_work *work)
fp); fp);
le32_add_cpu(&rsp->CreateContextsLength, le32_add_cpu(&rsp->CreateContextsLength,
conn->vals->create_posix_size); conn->vals->create_posix_size);
inc_rfc1001_len(work->response_buf, iov_len += conn->vals->create_posix_size;
conn->vals->create_posix_size);
if (next_ptr) if (next_ptr)
*next_ptr = cpu_to_le32(next_off); *next_ptr = cpu_to_le32(next_off);
} }
...@@ -3337,7 +3370,8 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3337,7 +3370,8 @@ int smb2_open(struct ksmbd_work *work)
} }
ksmbd_revert_fsids(work); ksmbd_revert_fsids(work);
err_out1: err_out1:
if (!rc)
rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len);
if (rc) { if (rc) {
if (rc == -EINVAL) if (rc == -EINVAL)
rsp->hdr.Status = STATUS_INVALID_PARAMETER; rsp->hdr.Status = STATUS_INVALID_PARAMETER;
...@@ -4063,7 +4097,10 @@ int smb2_query_dir(struct ksmbd_work *work) ...@@ -4063,7 +4097,10 @@ int smb2_query_dir(struct ksmbd_work *work)
rsp->OutputBufferOffset = cpu_to_le16(0); rsp->OutputBufferOffset = cpu_to_le16(0);
rsp->OutputBufferLength = cpu_to_le32(0); rsp->OutputBufferLength = cpu_to_le32(0);
rsp->Buffer[0] = 0; rsp->Buffer[0] = 0;
inc_rfc1001_len(work->response_buf, 9); rc = ksmbd_iov_pin_rsp(work, (void *)rsp,
sizeof(struct smb2_query_directory_rsp));
if (rc)
goto err_out;
} else { } else {
no_buf_len: no_buf_len:
((struct file_directory_info *) ((struct file_directory_info *)
...@@ -4075,7 +4112,11 @@ int smb2_query_dir(struct ksmbd_work *work) ...@@ -4075,7 +4112,11 @@ int smb2_query_dir(struct ksmbd_work *work)
rsp->StructureSize = cpu_to_le16(9); rsp->StructureSize = cpu_to_le16(9);
rsp->OutputBufferOffset = cpu_to_le16(72); rsp->OutputBufferOffset = cpu_to_le16(72);
rsp->OutputBufferLength = cpu_to_le32(d_info.data_count); rsp->OutputBufferLength = cpu_to_le32(d_info.data_count);
inc_rfc1001_len(work->response_buf, 8 + d_info.data_count); rc = ksmbd_iov_pin_rsp(work, (void *)rsp,
offsetof(struct smb2_query_directory_rsp, Buffer) +
d_info.data_count);
if (rc)
goto err_out;
} }
kfree(srch_ptr); kfree(srch_ptr);
...@@ -4116,28 +4157,19 @@ int smb2_query_dir(struct ksmbd_work *work) ...@@ -4116,28 +4157,19 @@ int smb2_query_dir(struct ksmbd_work *work)
* @reqOutputBufferLength: max buffer length expected in command response * @reqOutputBufferLength: max buffer length expected in command response
* @rsp: query info response buffer contains output buffer length * @rsp: query info response buffer contains output buffer length
* @rsp_org: base response buffer pointer in case of chained response * @rsp_org: base response buffer pointer in case of chained response
* @infoclass_size: query info class response buffer size
* *
* Return: 0 on success, otherwise error * Return: 0 on success, otherwise error
*/ */
static int buffer_check_err(int reqOutputBufferLength, static int buffer_check_err(int reqOutputBufferLength,
struct smb2_query_info_rsp *rsp, struct smb2_query_info_rsp *rsp,
void *rsp_org, int infoclass_size) void *rsp_org)
{ {
if (reqOutputBufferLength < le32_to_cpu(rsp->OutputBufferLength)) { if (reqOutputBufferLength < le32_to_cpu(rsp->OutputBufferLength)) {
if (reqOutputBufferLength < infoclass_size) {
pr_err("Invalid Buffer Size Requested\n"); pr_err("Invalid Buffer Size Requested\n");
rsp->hdr.Status = STATUS_INFO_LENGTH_MISMATCH; rsp->hdr.Status = STATUS_INFO_LENGTH_MISMATCH;
*(__be32 *)rsp_org = cpu_to_be32(sizeof(struct smb2_hdr)); *(__be32 *)rsp_org = cpu_to_be32(sizeof(struct smb2_hdr));
return -EINVAL; return -EINVAL;
} }
ksmbd_debug(SMB, "Buffer Overflow\n");
rsp->hdr.Status = STATUS_BUFFER_OVERFLOW;
*(__be32 *)rsp_org = cpu_to_be32(sizeof(struct smb2_hdr) +
reqOutputBufferLength);
rsp->OutputBufferLength = cpu_to_le32(reqOutputBufferLength);
}
return 0; return 0;
} }
...@@ -4155,7 +4187,6 @@ static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp, ...@@ -4155,7 +4187,6 @@ static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp,
sinfo->Directory = 0; sinfo->Directory = 0;
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_standard_info)); cpu_to_le32(sizeof(struct smb2_file_standard_info));
inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_standard_info));
} }
static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num, static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num,
...@@ -4169,7 +4200,6 @@ static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num, ...@@ -4169,7 +4200,6 @@ static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num,
file_info->IndexNumber = cpu_to_le64(num | (1ULL << 63)); file_info->IndexNumber = cpu_to_le64(num | (1ULL << 63));
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_internal_info)); cpu_to_le32(sizeof(struct smb2_file_internal_info));
inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_internal_info));
} }
static int smb2_get_info_file_pipe(struct ksmbd_session *sess, static int smb2_get_info_file_pipe(struct ksmbd_session *sess,
...@@ -4195,14 +4225,12 @@ static int smb2_get_info_file_pipe(struct ksmbd_session *sess, ...@@ -4195,14 +4225,12 @@ static int smb2_get_info_file_pipe(struct ksmbd_session *sess,
case FILE_STANDARD_INFORMATION: case FILE_STANDARD_INFORMATION:
get_standard_info_pipe(rsp, rsp_org); get_standard_info_pipe(rsp, rsp_org);
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
rsp, rsp_org, rsp, rsp_org);
FILE_STANDARD_INFORMATION_SIZE);
break; break;
case FILE_INTERNAL_INFORMATION: case FILE_INTERNAL_INFORMATION:
get_internal_info_pipe(rsp, id, rsp_org); get_internal_info_pipe(rsp, id, rsp_org);
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
rsp, rsp_org, rsp, rsp_org);
FILE_INTERNAL_INFORMATION_SIZE);
break; break;
default: default:
ksmbd_debug(SMB, "smb2_info_file_pipe for %u not supported\n", ksmbd_debug(SMB, "smb2_info_file_pipe for %u not supported\n",
...@@ -4308,7 +4336,7 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp, ...@@ -4308,7 +4336,7 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,
if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
name_len -= XATTR_USER_PREFIX_LEN; name_len -= XATTR_USER_PREFIX_LEN;
ptr = (char *)(&eainfo->name + name_len + 1); ptr = eainfo->name + name_len + 1;
buf_free_len -= (offsetof(struct smb2_ea_info, name) + buf_free_len -= (offsetof(struct smb2_ea_info, name) +
name_len + 1); name_len + 1);
/* bailout if xattr can't fit in buf_free_len */ /* bailout if xattr can't fit in buf_free_len */
...@@ -4370,7 +4398,6 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp, ...@@ -4370,7 +4398,6 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,
if (rsp_data_cnt == 0) if (rsp_data_cnt == 0)
rsp->hdr.Status = STATUS_NO_EAS_ON_FILE; rsp->hdr.Status = STATUS_NO_EAS_ON_FILE;
rsp->OutputBufferLength = cpu_to_le32(rsp_data_cnt); rsp->OutputBufferLength = cpu_to_le32(rsp_data_cnt);
inc_rfc1001_len(rsp_org, rsp_data_cnt);
out: out:
kvfree(xattr_list); kvfree(xattr_list);
return rc; return rc;
...@@ -4385,7 +4412,6 @@ static void get_file_access_info(struct smb2_query_info_rsp *rsp, ...@@ -4385,7 +4412,6 @@ static void get_file_access_info(struct smb2_query_info_rsp *rsp,
file_info->AccessFlags = fp->daccess; file_info->AccessFlags = fp->daccess;
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_access_info)); cpu_to_le32(sizeof(struct smb2_file_access_info));
inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_access_info));
} }
static int get_file_basic_info(struct smb2_query_info_rsp *rsp, static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
...@@ -4415,7 +4441,6 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp, ...@@ -4415,7 +4441,6 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
basic_info->Pad1 = 0; basic_info->Pad1 = 0;
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_basic_info)); cpu_to_le32(sizeof(struct smb2_file_basic_info));
inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_basic_info));
return 0; return 0;
} }
...@@ -4440,8 +4465,6 @@ static void get_file_standard_info(struct smb2_query_info_rsp *rsp, ...@@ -4440,8 +4465,6 @@ static void get_file_standard_info(struct smb2_query_info_rsp *rsp,
sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0; sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0;
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_standard_info)); cpu_to_le32(sizeof(struct smb2_file_standard_info));
inc_rfc1001_len(rsp_org,
sizeof(struct smb2_file_standard_info));
} }
static void get_file_alignment_info(struct smb2_query_info_rsp *rsp, static void get_file_alignment_info(struct smb2_query_info_rsp *rsp,
...@@ -4453,8 +4476,6 @@ static void get_file_alignment_info(struct smb2_query_info_rsp *rsp, ...@@ -4453,8 +4476,6 @@ static void get_file_alignment_info(struct smb2_query_info_rsp *rsp,
file_info->AlignmentRequirement = 0; file_info->AlignmentRequirement = 0;
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_alignment_info)); cpu_to_le32(sizeof(struct smb2_file_alignment_info));
inc_rfc1001_len(rsp_org,
sizeof(struct smb2_file_alignment_info));
} }
static int get_file_all_info(struct ksmbd_work *work, static int get_file_all_info(struct ksmbd_work *work,
...@@ -4518,7 +4539,6 @@ static int get_file_all_info(struct ksmbd_work *work, ...@@ -4518,7 +4539,6 @@ static int get_file_all_info(struct ksmbd_work *work,
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_all_info) + conv_len - 1); cpu_to_le32(sizeof(struct smb2_file_all_info) + conv_len - 1);
kfree(filename); kfree(filename);
inc_rfc1001_len(rsp_org, le32_to_cpu(rsp->OutputBufferLength));
return 0; return 0;
} }
...@@ -4541,7 +4561,6 @@ static void get_file_alternate_info(struct ksmbd_work *work, ...@@ -4541,7 +4561,6 @@ static void get_file_alternate_info(struct ksmbd_work *work,
file_info->FileNameLength = cpu_to_le32(conv_len); file_info->FileNameLength = cpu_to_le32(conv_len);
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_alt_name_info) + conv_len); cpu_to_le32(sizeof(struct smb2_file_alt_name_info) + conv_len);
inc_rfc1001_len(rsp_org, le32_to_cpu(rsp->OutputBufferLength));
} }
static void get_file_stream_info(struct ksmbd_work *work, static void get_file_stream_info(struct ksmbd_work *work,
...@@ -4641,7 +4660,6 @@ static void get_file_stream_info(struct ksmbd_work *work, ...@@ -4641,7 +4660,6 @@ static void get_file_stream_info(struct ksmbd_work *work,
kvfree(xattr_list); kvfree(xattr_list);
rsp->OutputBufferLength = cpu_to_le32(nbytes); rsp->OutputBufferLength = cpu_to_le32(nbytes);
inc_rfc1001_len(rsp_org, nbytes);
} }
static void get_file_internal_info(struct smb2_query_info_rsp *rsp, static void get_file_internal_info(struct smb2_query_info_rsp *rsp,
...@@ -4656,7 +4674,6 @@ static void get_file_internal_info(struct smb2_query_info_rsp *rsp, ...@@ -4656,7 +4674,6 @@ static void get_file_internal_info(struct smb2_query_info_rsp *rsp,
file_info->IndexNumber = cpu_to_le64(stat.ino); file_info->IndexNumber = cpu_to_le64(stat.ino);
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_internal_info)); cpu_to_le32(sizeof(struct smb2_file_internal_info));
inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_internal_info));
} }
static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
...@@ -4692,7 +4709,6 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, ...@@ -4692,7 +4709,6 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
file_info->Reserved = cpu_to_le32(0); file_info->Reserved = cpu_to_le32(0);
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_ntwrk_info)); cpu_to_le32(sizeof(struct smb2_file_ntwrk_info));
inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_ntwrk_info));
return 0; return 0;
} }
...@@ -4704,7 +4720,6 @@ static void get_file_ea_info(struct smb2_query_info_rsp *rsp, void *rsp_org) ...@@ -4704,7 +4720,6 @@ static void get_file_ea_info(struct smb2_query_info_rsp *rsp, void *rsp_org)
file_info->EASize = 0; file_info->EASize = 0;
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_ea_info)); cpu_to_le32(sizeof(struct smb2_file_ea_info));
inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_ea_info));
} }
static void get_file_position_info(struct smb2_query_info_rsp *rsp, static void get_file_position_info(struct smb2_query_info_rsp *rsp,
...@@ -4716,7 +4731,6 @@ static void get_file_position_info(struct smb2_query_info_rsp *rsp, ...@@ -4716,7 +4731,6 @@ static void get_file_position_info(struct smb2_query_info_rsp *rsp,
file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos); file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_pos_info)); cpu_to_le32(sizeof(struct smb2_file_pos_info));
inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_pos_info));
} }
static void get_file_mode_info(struct smb2_query_info_rsp *rsp, static void get_file_mode_info(struct smb2_query_info_rsp *rsp,
...@@ -4728,7 +4742,6 @@ static void get_file_mode_info(struct smb2_query_info_rsp *rsp, ...@@ -4728,7 +4742,6 @@ static void get_file_mode_info(struct smb2_query_info_rsp *rsp,
file_info->Mode = fp->coption & FILE_MODE_INFO_MASK; file_info->Mode = fp->coption & FILE_MODE_INFO_MASK;
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_mode_info)); cpu_to_le32(sizeof(struct smb2_file_mode_info));
inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_mode_info));
} }
static void get_file_compression_info(struct smb2_query_info_rsp *rsp, static void get_file_compression_info(struct smb2_query_info_rsp *rsp,
...@@ -4750,7 +4763,6 @@ static void get_file_compression_info(struct smb2_query_info_rsp *rsp, ...@@ -4750,7 +4763,6 @@ static void get_file_compression_info(struct smb2_query_info_rsp *rsp,
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_comp_info)); cpu_to_le32(sizeof(struct smb2_file_comp_info));
inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_comp_info));
} }
static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp, static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp,
...@@ -4769,11 +4781,10 @@ static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp, ...@@ -4769,11 +4781,10 @@ static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp,
file_info->ReparseTag = 0; file_info->ReparseTag = 0;
rsp->OutputBufferLength = rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_attr_tag_info)); cpu_to_le32(sizeof(struct smb2_file_attr_tag_info));
inc_rfc1001_len(rsp_org, sizeof(struct smb2_file_attr_tag_info));
return 0; return 0;
} }
static int find_file_posix_info(struct smb2_query_info_rsp *rsp, static void find_file_posix_info(struct smb2_query_info_rsp *rsp,
struct ksmbd_file *fp, void *rsp_org) struct ksmbd_file *fp, void *rsp_org)
{ {
struct smb311_posix_qinfo *file_info; struct smb311_posix_qinfo *file_info;
...@@ -4811,8 +4822,6 @@ static int find_file_posix_info(struct smb2_query_info_rsp *rsp, ...@@ -4811,8 +4822,6 @@ static int find_file_posix_info(struct smb2_query_info_rsp *rsp,
SIDUNIX_GROUP, (struct smb_sid *)&file_info->Sids[16]); SIDUNIX_GROUP, (struct smb_sid *)&file_info->Sids[16]);
rsp->OutputBufferLength = cpu_to_le32(out_buf_len); rsp->OutputBufferLength = cpu_to_le32(out_buf_len);
inc_rfc1001_len(rsp_org, out_buf_len);
return out_buf_len;
} }
static int smb2_get_info_file(struct ksmbd_work *work, static int smb2_get_info_file(struct ksmbd_work *work,
...@@ -4822,7 +4831,6 @@ static int smb2_get_info_file(struct ksmbd_work *work, ...@@ -4822,7 +4831,6 @@ static int smb2_get_info_file(struct ksmbd_work *work,
struct ksmbd_file *fp; struct ksmbd_file *fp;
int fileinfoclass = 0; int fileinfoclass = 0;
int rc = 0; int rc = 0;
int file_infoclass_size;
unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID; unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
if (test_share_config_flag(work->tcon->share_conf, if (test_share_config_flag(work->tcon->share_conf,
...@@ -4855,85 +4863,69 @@ static int smb2_get_info_file(struct ksmbd_work *work, ...@@ -4855,85 +4863,69 @@ static int smb2_get_info_file(struct ksmbd_work *work,
switch (fileinfoclass) { switch (fileinfoclass) {
case FILE_ACCESS_INFORMATION: case FILE_ACCESS_INFORMATION:
get_file_access_info(rsp, fp, work->response_buf); get_file_access_info(rsp, fp, work->response_buf);
file_infoclass_size = FILE_ACCESS_INFORMATION_SIZE;
break; break;
case FILE_BASIC_INFORMATION: case FILE_BASIC_INFORMATION:
rc = get_file_basic_info(rsp, fp, work->response_buf); rc = get_file_basic_info(rsp, fp, work->response_buf);
file_infoclass_size = FILE_BASIC_INFORMATION_SIZE;
break; break;
case FILE_STANDARD_INFORMATION: case FILE_STANDARD_INFORMATION:
get_file_standard_info(rsp, fp, work->response_buf); get_file_standard_info(rsp, fp, work->response_buf);
file_infoclass_size = FILE_STANDARD_INFORMATION_SIZE;
break; break;
case FILE_ALIGNMENT_INFORMATION: case FILE_ALIGNMENT_INFORMATION:
get_file_alignment_info(rsp, work->response_buf); get_file_alignment_info(rsp, work->response_buf);
file_infoclass_size = FILE_ALIGNMENT_INFORMATION_SIZE;
break; break;
case FILE_ALL_INFORMATION: case FILE_ALL_INFORMATION:
rc = get_file_all_info(work, rsp, fp, work->response_buf); rc = get_file_all_info(work, rsp, fp, work->response_buf);
file_infoclass_size = FILE_ALL_INFORMATION_SIZE;
break; break;
case FILE_ALTERNATE_NAME_INFORMATION: case FILE_ALTERNATE_NAME_INFORMATION:
get_file_alternate_info(work, rsp, fp, work->response_buf); get_file_alternate_info(work, rsp, fp, work->response_buf);
file_infoclass_size = FILE_ALTERNATE_NAME_INFORMATION_SIZE;
break; break;
case FILE_STREAM_INFORMATION: case FILE_STREAM_INFORMATION:
get_file_stream_info(work, rsp, fp, work->response_buf); get_file_stream_info(work, rsp, fp, work->response_buf);
file_infoclass_size = FILE_STREAM_INFORMATION_SIZE;
break; break;
case FILE_INTERNAL_INFORMATION: case FILE_INTERNAL_INFORMATION:
get_file_internal_info(rsp, fp, work->response_buf); get_file_internal_info(rsp, fp, work->response_buf);
file_infoclass_size = FILE_INTERNAL_INFORMATION_SIZE;
break; break;
case FILE_NETWORK_OPEN_INFORMATION: case FILE_NETWORK_OPEN_INFORMATION:
rc = get_file_network_open_info(rsp, fp, work->response_buf); rc = get_file_network_open_info(rsp, fp, work->response_buf);
file_infoclass_size = FILE_NETWORK_OPEN_INFORMATION_SIZE;
break; break;
case FILE_EA_INFORMATION: case FILE_EA_INFORMATION:
get_file_ea_info(rsp, work->response_buf); get_file_ea_info(rsp, work->response_buf);
file_infoclass_size = FILE_EA_INFORMATION_SIZE;
break; break;
case FILE_FULL_EA_INFORMATION: case FILE_FULL_EA_INFORMATION:
rc = smb2_get_ea(work, fp, req, rsp, work->response_buf); rc = smb2_get_ea(work, fp, req, rsp, work->response_buf);
file_infoclass_size = FILE_FULL_EA_INFORMATION_SIZE;
break; break;
case FILE_POSITION_INFORMATION: case FILE_POSITION_INFORMATION:
get_file_position_info(rsp, fp, work->response_buf); get_file_position_info(rsp, fp, work->response_buf);
file_infoclass_size = FILE_POSITION_INFORMATION_SIZE;
break; break;
case FILE_MODE_INFORMATION: case FILE_MODE_INFORMATION:
get_file_mode_info(rsp, fp, work->response_buf); get_file_mode_info(rsp, fp, work->response_buf);
file_infoclass_size = FILE_MODE_INFORMATION_SIZE;
break; break;
case FILE_COMPRESSION_INFORMATION: case FILE_COMPRESSION_INFORMATION:
get_file_compression_info(rsp, fp, work->response_buf); get_file_compression_info(rsp, fp, work->response_buf);
file_infoclass_size = FILE_COMPRESSION_INFORMATION_SIZE;
break; break;
case FILE_ATTRIBUTE_TAG_INFORMATION: case FILE_ATTRIBUTE_TAG_INFORMATION:
rc = get_file_attribute_tag_info(rsp, fp, work->response_buf); rc = get_file_attribute_tag_info(rsp, fp, work->response_buf);
file_infoclass_size = FILE_ATTRIBUTE_TAG_INFORMATION_SIZE;
break; break;
case SMB_FIND_FILE_POSIX_INFO: case SMB_FIND_FILE_POSIX_INFO:
if (!work->tcon->posix_extensions) { if (!work->tcon->posix_extensions) {
pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n");
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
} else { } else {
file_infoclass_size = find_file_posix_info(rsp, fp, find_file_posix_info(rsp, fp, work->response_buf);
work->response_buf);
} }
break; break;
default: default:
...@@ -4943,8 +4935,7 @@ static int smb2_get_info_file(struct ksmbd_work *work, ...@@ -4943,8 +4935,7 @@ static int smb2_get_info_file(struct ksmbd_work *work,
} }
if (!rc) if (!rc)
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
rsp, work->response_buf, rsp, work->response_buf);
file_infoclass_size);
ksmbd_fd_put(work, fp); ksmbd_fd_put(work, fp);
return rc; return rc;
} }
...@@ -4960,7 +4951,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -4960,7 +4951,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
struct kstatfs stfs; struct kstatfs stfs;
struct path path; struct path path;
int rc = 0, len; int rc = 0, len;
int fs_infoclass_size = 0;
if (!share->path) if (!share->path)
return -EIO; return -EIO;
...@@ -4990,8 +4980,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -4990,8 +4980,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->DeviceType = cpu_to_le32(stfs.f_type); info->DeviceType = cpu_to_le32(stfs.f_type);
info->DeviceCharacteristics = cpu_to_le32(0x00000020); info->DeviceCharacteristics = cpu_to_le32(0x00000020);
rsp->OutputBufferLength = cpu_to_le32(8); rsp->OutputBufferLength = cpu_to_le32(8);
inc_rfc1001_len(work->response_buf, 8);
fs_infoclass_size = FS_DEVICE_INFORMATION_SIZE;
break; break;
} }
case FS_ATTRIBUTE_INFORMATION: case FS_ATTRIBUTE_INFORMATION:
...@@ -5020,8 +5008,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -5020,8 +5008,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->FileSystemNameLen = cpu_to_le32(len); info->FileSystemNameLen = cpu_to_le32(len);
sz = sizeof(struct filesystem_attribute_info) - 2 + len; sz = sizeof(struct filesystem_attribute_info) - 2 + len;
rsp->OutputBufferLength = cpu_to_le32(sz); rsp->OutputBufferLength = cpu_to_le32(sz);
inc_rfc1001_len(work->response_buf, sz);
fs_infoclass_size = FS_ATTRIBUTE_INFORMATION_SIZE;
break; break;
} }
case FS_VOLUME_INFORMATION: case FS_VOLUME_INFORMATION:
...@@ -5048,8 +5034,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -5048,8 +5034,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->Reserved = 0; info->Reserved = 0;
sz = sizeof(struct filesystem_vol_info) - 2 + len; sz = sizeof(struct filesystem_vol_info) - 2 + len;
rsp->OutputBufferLength = cpu_to_le32(sz); rsp->OutputBufferLength = cpu_to_le32(sz);
inc_rfc1001_len(work->response_buf, sz);
fs_infoclass_size = FS_VOLUME_INFORMATION_SIZE;
break; break;
} }
case FS_SIZE_INFORMATION: case FS_SIZE_INFORMATION:
...@@ -5062,8 +5046,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -5062,8 +5046,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->SectorsPerAllocationUnit = cpu_to_le32(1); info->SectorsPerAllocationUnit = cpu_to_le32(1);
info->BytesPerSector = cpu_to_le32(stfs.f_bsize); info->BytesPerSector = cpu_to_le32(stfs.f_bsize);
rsp->OutputBufferLength = cpu_to_le32(24); rsp->OutputBufferLength = cpu_to_le32(24);
inc_rfc1001_len(work->response_buf, 24);
fs_infoclass_size = FS_SIZE_INFORMATION_SIZE;
break; break;
} }
case FS_FULL_SIZE_INFORMATION: case FS_FULL_SIZE_INFORMATION:
...@@ -5079,8 +5061,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -5079,8 +5061,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->SectorsPerAllocationUnit = cpu_to_le32(1); info->SectorsPerAllocationUnit = cpu_to_le32(1);
info->BytesPerSector = cpu_to_le32(stfs.f_bsize); info->BytesPerSector = cpu_to_le32(stfs.f_bsize);
rsp->OutputBufferLength = cpu_to_le32(32); rsp->OutputBufferLength = cpu_to_le32(32);
inc_rfc1001_len(work->response_buf, 32);
fs_infoclass_size = FS_FULL_SIZE_INFORMATION_SIZE;
break; break;
} }
case FS_OBJECT_ID_INFORMATION: case FS_OBJECT_ID_INFORMATION:
...@@ -5100,8 +5080,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -5100,8 +5080,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->extended_info.rel_date = 0; info->extended_info.rel_date = 0;
memcpy(info->extended_info.version_string, "1.1.0", strlen("1.1.0")); memcpy(info->extended_info.version_string, "1.1.0", strlen("1.1.0"));
rsp->OutputBufferLength = cpu_to_le32(64); rsp->OutputBufferLength = cpu_to_le32(64);
inc_rfc1001_len(work->response_buf, 64);
fs_infoclass_size = FS_OBJECT_ID_INFORMATION_SIZE;
break; break;
} }
case FS_SECTOR_SIZE_INFORMATION: case FS_SECTOR_SIZE_INFORMATION:
...@@ -5123,8 +5101,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -5123,8 +5101,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->ByteOffsetForSectorAlignment = 0; info->ByteOffsetForSectorAlignment = 0;
info->ByteOffsetForPartitionAlignment = 0; info->ByteOffsetForPartitionAlignment = 0;
rsp->OutputBufferLength = cpu_to_le32(28); rsp->OutputBufferLength = cpu_to_le32(28);
inc_rfc1001_len(work->response_buf, 28);
fs_infoclass_size = FS_SECTOR_SIZE_INFORMATION_SIZE;
break; break;
} }
case FS_CONTROL_INFORMATION: case FS_CONTROL_INFORMATION:
...@@ -5145,8 +5121,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -5145,8 +5121,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->DefaultQuotaLimit = cpu_to_le64(SMB2_NO_FID); info->DefaultQuotaLimit = cpu_to_le64(SMB2_NO_FID);
info->Padding = 0; info->Padding = 0;
rsp->OutputBufferLength = cpu_to_le32(48); rsp->OutputBufferLength = cpu_to_le32(48);
inc_rfc1001_len(work->response_buf, 48);
fs_infoclass_size = FS_CONTROL_INFORMATION_SIZE;
break; break;
} }
case FS_POSIX_INFORMATION: case FS_POSIX_INFORMATION:
...@@ -5166,8 +5140,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -5166,8 +5140,6 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->TotalFileNodes = cpu_to_le64(stfs.f_files); info->TotalFileNodes = cpu_to_le64(stfs.f_files);
info->FreeFileNodes = cpu_to_le64(stfs.f_ffree); info->FreeFileNodes = cpu_to_le64(stfs.f_ffree);
rsp->OutputBufferLength = cpu_to_le32(56); rsp->OutputBufferLength = cpu_to_le32(56);
inc_rfc1001_len(work->response_buf, 56);
fs_infoclass_size = FS_POSIX_INFORMATION_SIZE;
} }
break; break;
} }
...@@ -5176,8 +5148,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -5176,8 +5148,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength),
rsp, work->response_buf, rsp, work->response_buf);
fs_infoclass_size);
path_put(&path); path_put(&path);
return rc; return rc;
} }
...@@ -5211,7 +5182,6 @@ static int smb2_get_info_sec(struct ksmbd_work *work, ...@@ -5211,7 +5182,6 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
secdesclen = sizeof(struct smb_ntsd); secdesclen = sizeof(struct smb_ntsd);
rsp->OutputBufferLength = cpu_to_le32(secdesclen); rsp->OutputBufferLength = cpu_to_le32(secdesclen);
inc_rfc1001_len(work->response_buf, secdesclen);
return 0; return 0;
} }
...@@ -5256,7 +5226,6 @@ static int smb2_get_info_sec(struct ksmbd_work *work, ...@@ -5256,7 +5226,6 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
return rc; return rc;
rsp->OutputBufferLength = cpu_to_le32(secdesclen); rsp->OutputBufferLength = cpu_to_le32(secdesclen);
inc_rfc1001_len(work->response_buf, secdesclen);
return 0; return 0;
} }
...@@ -5295,6 +5264,14 @@ int smb2_query_info(struct ksmbd_work *work) ...@@ -5295,6 +5264,14 @@ int smb2_query_info(struct ksmbd_work *work)
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
} }
if (!rc) {
rsp->StructureSize = cpu_to_le16(9);
rsp->OutputBufferOffset = cpu_to_le16(72);
rc = ksmbd_iov_pin_rsp(work, (void *)rsp,
offsetof(struct smb2_query_info_rsp, Buffer) +
le32_to_cpu(rsp->OutputBufferLength));
}
if (rc < 0) { if (rc < 0) {
if (rc == -EACCES) if (rc == -EACCES)
rsp->hdr.Status = STATUS_ACCESS_DENIED; rsp->hdr.Status = STATUS_ACCESS_DENIED;
...@@ -5302,6 +5279,8 @@ int smb2_query_info(struct ksmbd_work *work) ...@@ -5302,6 +5279,8 @@ int smb2_query_info(struct ksmbd_work *work)
rsp->hdr.Status = STATUS_FILE_CLOSED; rsp->hdr.Status = STATUS_FILE_CLOSED;
else if (rc == -EIO) else if (rc == -EIO)
rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR; rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;
else if (rc == -ENOMEM)
rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
else if (rc == -EOPNOTSUPP || rsp->hdr.Status == 0) else if (rc == -EOPNOTSUPP || rsp->hdr.Status == 0)
rsp->hdr.Status = STATUS_INVALID_INFO_CLASS; rsp->hdr.Status = STATUS_INVALID_INFO_CLASS;
smb2_set_err_rsp(work); smb2_set_err_rsp(work);
...@@ -5310,9 +5289,6 @@ int smb2_query_info(struct ksmbd_work *work) ...@@ -5310,9 +5289,6 @@ int smb2_query_info(struct ksmbd_work *work)
rc); rc);
return rc; return rc;
} }
rsp->StructureSize = cpu_to_le16(9);
rsp->OutputBufferOffset = cpu_to_le16(72);
inc_rfc1001_len(work->response_buf, 8);
return 0; return 0;
} }
...@@ -5343,8 +5319,9 @@ static noinline int smb2_close_pipe(struct ksmbd_work *work) ...@@ -5343,8 +5319,9 @@ static noinline int smb2_close_pipe(struct ksmbd_work *work)
rsp->AllocationSize = 0; rsp->AllocationSize = 0;
rsp->EndOfFile = 0; rsp->EndOfFile = 0;
rsp->Attributes = 0; rsp->Attributes = 0;
inc_rfc1001_len(work->response_buf, 60);
return 0; return ksmbd_iov_pin_rsp(work, (void *)rsp,
sizeof(struct smb2_close_rsp));
} }
/** /**
...@@ -5449,15 +5426,17 @@ int smb2_close(struct ksmbd_work *work) ...@@ -5449,15 +5426,17 @@ int smb2_close(struct ksmbd_work *work)
err = ksmbd_close_fd(work, volatile_id); err = ksmbd_close_fd(work, volatile_id);
out: out:
if (!err)
err = ksmbd_iov_pin_rsp(work, (void *)rsp,
sizeof(struct smb2_close_rsp));
if (err) { if (err) {
if (rsp->hdr.Status == 0) if (rsp->hdr.Status == 0)
rsp->hdr.Status = STATUS_FILE_CLOSED; rsp->hdr.Status = STATUS_FILE_CLOSED;
smb2_set_err_rsp(work); smb2_set_err_rsp(work);
} else {
inc_rfc1001_len(work->response_buf, 60);
} }
return 0; return err;
} }
/** /**
...@@ -5475,8 +5454,7 @@ int smb2_echo(struct ksmbd_work *work) ...@@ -5475,8 +5454,7 @@ int smb2_echo(struct ksmbd_work *work)
rsp->StructureSize = cpu_to_le16(4); rsp->StructureSize = cpu_to_le16(4);
rsp->Reserved = 0; rsp->Reserved = 0;
inc_rfc1001_len(work->response_buf, 4); return ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_echo_rsp));
return 0;
} }
static int smb2_rename(struct ksmbd_work *work, static int smb2_rename(struct ksmbd_work *work,
...@@ -6068,7 +6046,10 @@ int smb2_set_info(struct ksmbd_work *work) ...@@ -6068,7 +6046,10 @@ int smb2_set_info(struct ksmbd_work *work)
goto err_out; goto err_out;
rsp->StructureSize = cpu_to_le16(2); rsp->StructureSize = cpu_to_le16(2);
inc_rfc1001_len(work->response_buf, 2); rc = ksmbd_iov_pin_rsp(work, (void *)rsp,
sizeof(struct smb2_set_info_rsp));
if (rc)
goto err_out;
ksmbd_fd_put(work, fp); ksmbd_fd_put(work, fp);
return 0; return 0;
...@@ -6115,28 +6096,36 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work) ...@@ -6115,28 +6096,36 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work)
id = req->VolatileFileId; id = req->VolatileFileId;
inc_rfc1001_len(work->response_buf, 16);
rpc_resp = ksmbd_rpc_read(work->sess, id); rpc_resp = ksmbd_rpc_read(work->sess, id);
if (rpc_resp) { if (rpc_resp) {
void *aux_payload_buf;
if (rpc_resp->flags != KSMBD_RPC_OK) { if (rpc_resp->flags != KSMBD_RPC_OK) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
work->aux_payload_buf = aux_payload_buf =
kvmalloc(rpc_resp->payload_sz, GFP_KERNEL); kvmalloc(rpc_resp->payload_sz, GFP_KERNEL);
if (!work->aux_payload_buf) { if (!aux_payload_buf) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }
memcpy(work->aux_payload_buf, rpc_resp->payload, memcpy(aux_payload_buf, rpc_resp->payload, rpc_resp->payload_sz);
rpc_resp->payload_sz);
nbytes = rpc_resp->payload_sz; nbytes = rpc_resp->payload_sz;
work->resp_hdr_sz = get_rfc1002_len(work->response_buf) + 4;
work->aux_payload_sz = nbytes;
kvfree(rpc_resp); kvfree(rpc_resp);
err = ksmbd_iov_pin_rsp_read(work, (void *)rsp,
offsetof(struct smb2_read_rsp, Buffer),
aux_payload_buf, nbytes);
if (err)
goto out;
} else {
err = ksmbd_iov_pin_rsp(work, (void *)rsp,
offsetof(struct smb2_read_rsp, Buffer));
if (err)
goto out;
} }
rsp->StructureSize = cpu_to_le16(17); rsp->StructureSize = cpu_to_le16(17);
...@@ -6145,7 +6134,6 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work) ...@@ -6145,7 +6134,6 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work)
rsp->DataLength = cpu_to_le32(nbytes); rsp->DataLength = cpu_to_le32(nbytes);
rsp->DataRemaining = 0; rsp->DataRemaining = 0;
rsp->Flags = 0; rsp->Flags = 0;
inc_rfc1001_len(work->response_buf, nbytes);
return 0; return 0;
out: out:
...@@ -6219,13 +6207,8 @@ int smb2_read(struct ksmbd_work *work) ...@@ -6219,13 +6207,8 @@ int smb2_read(struct ksmbd_work *work)
int err = 0; int err = 0;
bool is_rdma_channel = false; bool is_rdma_channel = false;
unsigned int max_read_size = conn->vals->max_read_size; unsigned int max_read_size = conn->vals->max_read_size;
unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
WORK_BUFFERS(work, req, rsp); void *aux_payload_buf;
if (work->next_smb2_rcv_hdr_off) {
work->send_no_response = 1;
err = -EOPNOTSUPP;
goto out;
}
if (test_share_config_flag(work->tcon->share_conf, if (test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_PIPE)) { KSMBD_SHARE_FLAG_PIPE)) {
...@@ -6233,6 +6216,25 @@ int smb2_read(struct ksmbd_work *work) ...@@ -6233,6 +6216,25 @@ int smb2_read(struct ksmbd_work *work)
return smb2_read_pipe(work); return smb2_read_pipe(work);
} }
if (work->next_smb2_rcv_hdr_off) {
req = ksmbd_req_buf_next(work);
rsp = ksmbd_resp_buf_next(work);
if (!has_file_id(req->VolatileFileId)) {
ksmbd_debug(SMB, "Compound request set FID = %llu\n",
work->compound_fid);
id = work->compound_fid;
pid = work->compound_pfid;
}
} else {
req = smb2_get_msg(work->request_buf);
rsp = smb2_get_msg(work->response_buf);
}
if (!has_file_id(id)) {
id = req->VolatileFileId;
pid = req->PersistentFileId;
}
if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE || if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE ||
req->Channel == SMB2_CHANNEL_RDMA_V1) { req->Channel == SMB2_CHANNEL_RDMA_V1) {
is_rdma_channel = true; is_rdma_channel = true;
...@@ -6255,7 +6257,7 @@ int smb2_read(struct ksmbd_work *work) ...@@ -6255,7 +6257,7 @@ int smb2_read(struct ksmbd_work *work)
goto out; goto out;
} }
fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); fp = ksmbd_lookup_fd_slow(work, id, pid);
if (!fp) { if (!fp) {
err = -ENOENT; err = -ENOENT;
goto out; goto out;
...@@ -6281,21 +6283,20 @@ int smb2_read(struct ksmbd_work *work) ...@@ -6281,21 +6283,20 @@ int smb2_read(struct ksmbd_work *work)
ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n", ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n",
fp->filp, offset, length); fp->filp, offset, length);
work->aux_payload_buf = kvzalloc(length, GFP_KERNEL); aux_payload_buf = kvzalloc(length, GFP_KERNEL);
if (!work->aux_payload_buf) { if (!aux_payload_buf) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }
nbytes = ksmbd_vfs_read(work, fp, length, &offset); nbytes = ksmbd_vfs_read(work, fp, length, &offset, aux_payload_buf);
if (nbytes < 0) { if (nbytes < 0) {
err = nbytes; err = nbytes;
goto out; goto out;
} }
if ((nbytes == 0 && length != 0) || nbytes < mincount) { if ((nbytes == 0 && length != 0) || nbytes < mincount) {
kvfree(work->aux_payload_buf); kvfree(aux_payload_buf);
work->aux_payload_buf = NULL;
rsp->hdr.Status = STATUS_END_OF_FILE; rsp->hdr.Status = STATUS_END_OF_FILE;
smb2_set_err_rsp(work); smb2_set_err_rsp(work);
ksmbd_fd_put(work, fp); ksmbd_fd_put(work, fp);
...@@ -6308,10 +6309,9 @@ int smb2_read(struct ksmbd_work *work) ...@@ -6308,10 +6309,9 @@ int smb2_read(struct ksmbd_work *work)
if (is_rdma_channel == true) { if (is_rdma_channel == true) {
/* write data to the client using rdma channel */ /* write data to the client using rdma channel */
remain_bytes = smb2_read_rdma_channel(work, req, remain_bytes = smb2_read_rdma_channel(work, req,
work->aux_payload_buf, aux_payload_buf,
nbytes); nbytes);
kvfree(work->aux_payload_buf); kvfree(aux_payload_buf);
work->aux_payload_buf = NULL;
nbytes = 0; nbytes = 0;
if (remain_bytes < 0) { if (remain_bytes < 0) {
...@@ -6326,10 +6326,11 @@ int smb2_read(struct ksmbd_work *work) ...@@ -6326,10 +6326,11 @@ int smb2_read(struct ksmbd_work *work)
rsp->DataLength = cpu_to_le32(nbytes); rsp->DataLength = cpu_to_le32(nbytes);
rsp->DataRemaining = cpu_to_le32(remain_bytes); rsp->DataRemaining = cpu_to_le32(remain_bytes);
rsp->Flags = 0; rsp->Flags = 0;
inc_rfc1001_len(work->response_buf, 16); err = ksmbd_iov_pin_rsp_read(work, (void *)rsp,
work->resp_hdr_sz = get_rfc1002_len(work->response_buf) + 4; offsetof(struct smb2_read_rsp, Buffer),
work->aux_payload_sz = nbytes; aux_payload_buf, nbytes);
inc_rfc1001_len(work->response_buf, nbytes); if (err)
goto out;
ksmbd_fd_put(work, fp); ksmbd_fd_put(work, fp);
return 0; return 0;
...@@ -6412,8 +6413,8 @@ static noinline int smb2_write_pipe(struct ksmbd_work *work) ...@@ -6412,8 +6413,8 @@ static noinline int smb2_write_pipe(struct ksmbd_work *work)
rsp->DataLength = cpu_to_le32(length); rsp->DataLength = cpu_to_le32(length);
rsp->DataRemaining = 0; rsp->DataRemaining = 0;
rsp->Reserved2 = 0; rsp->Reserved2 = 0;
inc_rfc1001_len(work->response_buf, 16); err = ksmbd_iov_pin_rsp(work, (void *)rsp,
return 0; offsetof(struct smb2_write_rsp, Buffer));
out: out:
if (err) { if (err) {
rsp->hdr.Status = STATUS_INVALID_HANDLE; rsp->hdr.Status = STATUS_INVALID_HANDLE;
...@@ -6569,7 +6570,9 @@ int smb2_write(struct ksmbd_work *work) ...@@ -6569,7 +6570,9 @@ int smb2_write(struct ksmbd_work *work)
rsp->DataLength = cpu_to_le32(nbytes); rsp->DataLength = cpu_to_le32(nbytes);
rsp->DataRemaining = 0; rsp->DataRemaining = 0;
rsp->Reserved2 = 0; rsp->Reserved2 = 0;
inc_rfc1001_len(work->response_buf, 16); err = ksmbd_iov_pin_rsp(work, rsp, offsetof(struct smb2_write_rsp, Buffer));
if (err)
goto out;
ksmbd_fd_put(work, fp); ksmbd_fd_put(work, fp);
return 0; return 0;
...@@ -6616,15 +6619,11 @@ int smb2_flush(struct ksmbd_work *work) ...@@ -6616,15 +6619,11 @@ int smb2_flush(struct ksmbd_work *work)
rsp->StructureSize = cpu_to_le16(4); rsp->StructureSize = cpu_to_le16(4);
rsp->Reserved = 0; rsp->Reserved = 0;
inc_rfc1001_len(work->response_buf, 4); return ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_flush_rsp));
return 0;
out: out:
if (err) {
rsp->hdr.Status = STATUS_INVALID_HANDLE; rsp->hdr.Status = STATUS_INVALID_HANDLE;
smb2_set_err_rsp(work); smb2_set_err_rsp(work);
}
return err; return err;
} }
...@@ -7078,8 +7077,6 @@ int smb2_lock(struct ksmbd_work *work) ...@@ -7078,8 +7077,6 @@ int smb2_lock(struct ksmbd_work *work)
goto out; goto out;
} }
init_smb2_rsp_hdr(work);
smb2_set_err_rsp(work);
rsp->hdr.Status = rsp->hdr.Status =
STATUS_RANGE_NOT_LOCKED; STATUS_RANGE_NOT_LOCKED;
kfree(smb_lock); kfree(smb_lock);
...@@ -7114,7 +7111,10 @@ int smb2_lock(struct ksmbd_work *work) ...@@ -7114,7 +7111,10 @@ int smb2_lock(struct ksmbd_work *work)
ksmbd_debug(SMB, "successful in taking lock\n"); ksmbd_debug(SMB, "successful in taking lock\n");
rsp->hdr.Status = STATUS_SUCCESS; rsp->hdr.Status = STATUS_SUCCESS;
rsp->Reserved = 0; rsp->Reserved = 0;
inc_rfc1001_len(work->response_buf, 4); err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_lock_rsp));
if (err)
goto out;
ksmbd_fd_put(work, fp); ksmbd_fd_put(work, fp);
return 0; return 0;
...@@ -7910,9 +7910,9 @@ int smb2_ioctl(struct ksmbd_work *work) ...@@ -7910,9 +7910,9 @@ int smb2_ioctl(struct ksmbd_work *work)
rsp->Reserved = cpu_to_le16(0); rsp->Reserved = cpu_to_le16(0);
rsp->Flags = cpu_to_le32(0); rsp->Flags = cpu_to_le32(0);
rsp->Reserved2 = cpu_to_le32(0); rsp->Reserved2 = cpu_to_le32(0);
inc_rfc1001_len(work->response_buf, 48 + nbytes); ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_ioctl_rsp) + nbytes);
if (!ret)
return 0; return ret;
out: out:
if (ret == -EACCES) if (ret == -EACCES)
...@@ -8047,7 +8047,8 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work) ...@@ -8047,7 +8047,8 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
rsp->Reserved2 = 0; rsp->Reserved2 = 0;
rsp->VolatileFid = volatile_id; rsp->VolatileFid = volatile_id;
rsp->PersistentFid = persistent_id; rsp->PersistentFid = persistent_id;
inc_rfc1001_len(work->response_buf, 24); ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_oplock_break));
if (!ret)
return; return;
err_out: err_out:
...@@ -8198,7 +8199,8 @@ static void smb21_lease_break_ack(struct ksmbd_work *work) ...@@ -8198,7 +8199,8 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
memcpy(rsp->LeaseKey, req->LeaseKey, 16); memcpy(rsp->LeaseKey, req->LeaseKey, 16);
rsp->LeaseState = lease_state; rsp->LeaseState = lease_state;
rsp->LeaseDuration = 0; rsp->LeaseDuration = 0;
inc_rfc1001_len(work->response_buf, 36); ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_lease_ack));
if (!ret)
return; return;
err_out: err_out:
...@@ -8337,43 +8339,19 @@ int smb2_check_sign_req(struct ksmbd_work *work) ...@@ -8337,43 +8339,19 @@ int smb2_check_sign_req(struct ksmbd_work *work)
void smb2_set_sign_rsp(struct ksmbd_work *work) void smb2_set_sign_rsp(struct ksmbd_work *work)
{ {
struct smb2_hdr *hdr; struct smb2_hdr *hdr;
struct smb2_hdr *req_hdr;
char signature[SMB2_HMACSHA256_SIZE]; char signature[SMB2_HMACSHA256_SIZE];
struct kvec iov[2]; struct kvec *iov;
size_t len;
int n_vec = 1; int n_vec = 1;
hdr = smb2_get_msg(work->response_buf); hdr = ksmbd_resp_buf_curr(work);
if (work->next_smb2_rsp_hdr_off)
hdr = ksmbd_resp_buf_next(work);
req_hdr = ksmbd_req_buf_next(work);
if (!work->next_smb2_rsp_hdr_off) {
len = get_rfc1002_len(work->response_buf);
if (req_hdr->NextCommand)
len = ALIGN(len, 8);
} else {
len = get_rfc1002_len(work->response_buf) -
work->next_smb2_rsp_hdr_off;
len = ALIGN(len, 8);
}
if (req_hdr->NextCommand)
hdr->NextCommand = cpu_to_le32(len);
hdr->Flags |= SMB2_FLAGS_SIGNED; hdr->Flags |= SMB2_FLAGS_SIGNED;
memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE); memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);
iov[0].iov_base = (char *)&hdr->ProtocolId; if (hdr->Command == SMB2_READ) {
iov[0].iov_len = len; iov = &work->iov[work->iov_idx - 1];
if (work->aux_payload_sz) {
iov[0].iov_len -= work->aux_payload_sz;
iov[1].iov_base = work->aux_payload_buf;
iov[1].iov_len = work->aux_payload_sz;
n_vec++; n_vec++;
} else {
iov = &work->iov[work->iov_idx];
} }
if (!ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, n_vec, if (!ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, n_vec,
...@@ -8449,29 +8427,14 @@ int smb3_check_sign_req(struct ksmbd_work *work) ...@@ -8449,29 +8427,14 @@ int smb3_check_sign_req(struct ksmbd_work *work)
void smb3_set_sign_rsp(struct ksmbd_work *work) void smb3_set_sign_rsp(struct ksmbd_work *work)
{ {
struct ksmbd_conn *conn = work->conn; struct ksmbd_conn *conn = work->conn;
struct smb2_hdr *req_hdr, *hdr; struct smb2_hdr *hdr;
struct channel *chann; struct channel *chann;
char signature[SMB2_CMACAES_SIZE]; char signature[SMB2_CMACAES_SIZE];
struct kvec iov[2]; struct kvec *iov;
int n_vec = 1; int n_vec = 1;
size_t len;
char *signing_key; char *signing_key;
hdr = smb2_get_msg(work->response_buf); hdr = ksmbd_resp_buf_curr(work);
if (work->next_smb2_rsp_hdr_off)
hdr = ksmbd_resp_buf_next(work);
req_hdr = ksmbd_req_buf_next(work);
if (!work->next_smb2_rsp_hdr_off) {
len = get_rfc1002_len(work->response_buf);
if (req_hdr->NextCommand)
len = ALIGN(len, 8);
} else {
len = get_rfc1002_len(work->response_buf) -
work->next_smb2_rsp_hdr_off;
len = ALIGN(len, 8);
}
if (conn->binding == false && if (conn->binding == false &&
le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
...@@ -8487,21 +8450,18 @@ void smb3_set_sign_rsp(struct ksmbd_work *work) ...@@ -8487,21 +8450,18 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
if (!signing_key) if (!signing_key)
return; return;
if (req_hdr->NextCommand)
hdr->NextCommand = cpu_to_le32(len);
hdr->Flags |= SMB2_FLAGS_SIGNED; hdr->Flags |= SMB2_FLAGS_SIGNED;
memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE); memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);
iov[0].iov_base = (char *)&hdr->ProtocolId;
iov[0].iov_len = len; if (hdr->Command == SMB2_READ) {
if (work->aux_payload_sz) { iov = &work->iov[work->iov_idx - 1];
iov[0].iov_len -= work->aux_payload_sz;
iov[1].iov_base = work->aux_payload_buf;
iov[1].iov_len = work->aux_payload_sz;
n_vec++; n_vec++;
} else {
iov = &work->iov[work->iov_idx];
} }
if (!ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec, signature)) if (!ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec,
signature))
memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE); memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE);
} }
...@@ -8568,45 +8528,22 @@ static void fill_transform_hdr(void *tr_buf, char *old_buf, __le16 cipher_type) ...@@ -8568,45 +8528,22 @@ static void fill_transform_hdr(void *tr_buf, char *old_buf, __le16 cipher_type)
int smb3_encrypt_resp(struct ksmbd_work *work) int smb3_encrypt_resp(struct ksmbd_work *work)
{ {
char *buf = work->response_buf; struct kvec *iov = work->iov;
struct kvec iov[3];
int rc = -ENOMEM; int rc = -ENOMEM;
int buf_size = 0, rq_nvec = 2 + (work->aux_payload_sz ? 1 : 0); void *tr_buf;
if (ARRAY_SIZE(iov) < rq_nvec)
return -ENOMEM;
work->tr_buf = kzalloc(sizeof(struct smb2_transform_hdr) + 4, GFP_KERNEL); tr_buf = kzalloc(sizeof(struct smb2_transform_hdr) + 4, GFP_KERNEL);
if (!work->tr_buf) if (!tr_buf)
return rc; return rc;
/* fill transform header */ /* fill transform header */
fill_transform_hdr(work->tr_buf, buf, work->conn->cipher_type); fill_transform_hdr(tr_buf, work->response_buf, work->conn->cipher_type);
iov[0].iov_base = work->tr_buf; iov[0].iov_base = tr_buf;
iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4; iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4;
buf_size += iov[0].iov_len - 4; work->tr_buf = tr_buf;
iov[1].iov_base = buf + 4;
iov[1].iov_len = get_rfc1002_len(buf);
if (work->aux_payload_sz) {
iov[1].iov_len = work->resp_hdr_sz - 4;
iov[2].iov_base = work->aux_payload_buf;
iov[2].iov_len = work->aux_payload_sz;
buf_size += iov[2].iov_len;
}
buf_size += iov[1].iov_len;
work->resp_hdr_sz = iov[1].iov_len;
rc = ksmbd_crypt_message(work, iov, rq_nvec, 1); return ksmbd_crypt_message(work, iov, work->iov_idx + 1, 1);
if (rc)
return rc;
memmove(buf, iov[1].iov_base, iov[1].iov_len);
*(__be32 *)work->tr_buf = cpu_to_be32(buf_size);
return rc;
} }
bool smb3_is_transform_hdr(void *buf) bool smb3_is_transform_hdr(void *buf)
......
...@@ -361,7 +361,7 @@ struct smb2_ea_info { ...@@ -361,7 +361,7 @@ struct smb2_ea_info {
__u8 Flags; __u8 Flags;
__u8 EaNameLength; __u8 EaNameLength;
__le16 EaValueLength; __le16 EaValueLength;
char name[1]; char name[];
/* optionally followed by value */ /* optionally followed by value */
} __packed; /* level 15 Query */ } __packed; /* level 15 Query */
......
...@@ -319,12 +319,6 @@ static int init_smb1_rsp_hdr(struct ksmbd_work *work) ...@@ -319,12 +319,6 @@ static int init_smb1_rsp_hdr(struct ksmbd_work *work)
struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf; struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf;
struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf; struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf;
/*
* Remove 4 byte direct TCP header.
*/
*(__be32 *)work->response_buf =
cpu_to_be32(sizeof(struct smb_hdr) - 4);
rsp_hdr->Command = SMB_COM_NEGOTIATE; rsp_hdr->Command = SMB_COM_NEGOTIATE;
*(__le32 *)rsp_hdr->Protocol = SMB1_PROTO_NUMBER; *(__le32 *)rsp_hdr->Protocol = SMB1_PROTO_NUMBER;
rsp_hdr->Flags = SMBFLG_RESPONSE; rsp_hdr->Flags = SMBFLG_RESPONSE;
...@@ -560,10 +554,11 @@ static int smb_handle_negotiate(struct ksmbd_work *work) ...@@ -560,10 +554,11 @@ static int smb_handle_negotiate(struct ksmbd_work *work)
ksmbd_debug(SMB, "Unsupported SMB1 protocol\n"); ksmbd_debug(SMB, "Unsupported SMB1 protocol\n");
/* Add 2 byte bcc and 2 byte DialectIndex. */ if (ksmbd_iov_pin_rsp(work, (void *)neg_rsp,
inc_rfc1001_len(work->response_buf, 4); sizeof(struct smb_negotiate_rsp) - 4))
neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS; return -ENOMEM;
neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS;
neg_rsp->hdr.WordCount = 1; neg_rsp->hdr.WordCount = 1;
neg_rsp->DialectIndex = cpu_to_le16(work->conn->dialect); neg_rsp->DialectIndex = cpu_to_le16(work->conn->dialect);
neg_rsp->ByteCount = 0; neg_rsp->ByteCount = 0;
......
...@@ -1241,14 +1241,12 @@ static int smb_direct_writev(struct ksmbd_transport *t, ...@@ -1241,14 +1241,12 @@ static int smb_direct_writev(struct ksmbd_transport *t,
//FIXME: skip RFC1002 header.. //FIXME: skip RFC1002 header..
buflen -= 4; buflen -= 4;
iov[0].iov_base += 4;
iov[0].iov_len -= 4;
remaining_data_length = buflen; remaining_data_length = buflen;
ksmbd_debug(RDMA, "Sending smb (RDMA): smb_len=%u\n", buflen); ksmbd_debug(RDMA, "Sending smb (RDMA): smb_len=%u\n", buflen);
smb_direct_send_ctx_init(st, &send_ctx, need_invalidate, remote_key); smb_direct_send_ctx_init(st, &send_ctx, need_invalidate, remote_key);
start = i = 0; start = i = 1;
buflen = 0; buflen = 0;
while (true) { while (true) {
buflen += iov[i].iov_len; buflen += iov[i].iov_len;
...@@ -1366,24 +1364,35 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, ...@@ -1366,24 +1364,35 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t,
LIST_HEAD(msg_list); LIST_HEAD(msg_list);
char *desc_buf; char *desc_buf;
int credits_needed; int credits_needed;
unsigned int desc_buf_len; unsigned int desc_buf_len, desc_num = 0;
size_t total_length = 0;
if (t->status != SMB_DIRECT_CS_CONNECTED) if (t->status != SMB_DIRECT_CS_CONNECTED)
return -ENOTCONN; return -ENOTCONN;
if (buf_len > t->max_rdma_rw_size)
return -EINVAL;
/* calculate needed credits */ /* calculate needed credits */
credits_needed = 0; credits_needed = 0;
desc_buf = buf; desc_buf = buf;
for (i = 0; i < desc_len / sizeof(*desc); i++) { for (i = 0; i < desc_len / sizeof(*desc); i++) {
if (!buf_len)
break;
desc_buf_len = le32_to_cpu(desc[i].length); desc_buf_len = le32_to_cpu(desc[i].length);
if (!desc_buf_len)
return -EINVAL;
if (desc_buf_len > buf_len) {
desc_buf_len = buf_len;
desc[i].length = cpu_to_le32(desc_buf_len);
buf_len = 0;
}
credits_needed += calc_rw_credits(t, desc_buf, desc_buf_len); credits_needed += calc_rw_credits(t, desc_buf, desc_buf_len);
desc_buf += desc_buf_len; desc_buf += desc_buf_len;
total_length += desc_buf_len; buf_len -= desc_buf_len;
if (desc_buf_len == 0 || total_length > buf_len || desc_num++;
total_length > t->max_rdma_rw_size)
return -EINVAL;
} }
ksmbd_debug(RDMA, "RDMA %s, len %#x, needed credits %#x\n", ksmbd_debug(RDMA, "RDMA %s, len %#x, needed credits %#x\n",
...@@ -1395,7 +1404,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, ...@@ -1395,7 +1404,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t,
/* build rdma_rw_ctx for each descriptor */ /* build rdma_rw_ctx for each descriptor */
desc_buf = buf; desc_buf = buf;
for (i = 0; i < desc_len / sizeof(*desc); i++) { for (i = 0; i < desc_num; i++) {
msg = kzalloc(offsetof(struct smb_direct_rdma_rw_msg, sg_list) + msg = kzalloc(offsetof(struct smb_direct_rdma_rw_msg, sg_list) +
sizeof(struct scatterlist) * SG_CHUNK_SIZE, GFP_KERNEL); sizeof(struct scatterlist) * SG_CHUNK_SIZE, GFP_KERNEL);
if (!msg) { if (!msg) {
......
...@@ -367,15 +367,15 @@ static int check_lock_range(struct file *filp, loff_t start, loff_t end, ...@@ -367,15 +367,15 @@ static int check_lock_range(struct file *filp, loff_t start, loff_t end,
* @fid: file id of open file * @fid: file id of open file
* @count: read byte count * @count: read byte count
* @pos: file pos * @pos: file pos
* @rbuf: read data buffer
* *
* Return: number of read bytes on success, otherwise error * Return: number of read bytes on success, otherwise error
*/ */
int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count, int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count,
loff_t *pos) loff_t *pos, char *rbuf)
{ {
struct file *filp = fp->filp; struct file *filp = fp->filp;
ssize_t nbytes = 0; ssize_t nbytes = 0;
char *rbuf = work->aux_payload_buf;
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
......
...@@ -76,8 +76,8 @@ void ksmbd_vfs_query_maximal_access(struct mnt_idmap *idmap, ...@@ -76,8 +76,8 @@ void ksmbd_vfs_query_maximal_access(struct mnt_idmap *idmap,
struct dentry *dentry, __le32 *daccess); struct dentry *dentry, __le32 *daccess);
int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode); int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode);
int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode); int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode);
int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count,
size_t count, loff_t *pos); loff_t *pos, char *rbuf);
int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp, int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp,
char *buf, size_t count, loff_t *pos, bool sync, char *buf, size_t count, loff_t *pos, bool sync,
ssize_t *written); ssize_t *written);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment