Skip to content

Commit 8ae5d29

Browse files
committed
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
2 parents 7e5cd6f + 0e2378e commit 8ae5d29

File tree

15 files changed

+432
-417
lines changed

15 files changed

+432
-417
lines changed

fs/smb/server/asn1.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,10 @@ static int ksmbd_neg_token_alloc(void *context, size_t hdrlen,
214214
{
215215
struct ksmbd_conn *conn = context;
216216

217-
conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL);
217+
conn->mechToken = kmemdup_nul(value, vlen, GFP_KERNEL);
218218
if (!conn->mechToken)
219219
return -ENOMEM;
220220

221-
memcpy(conn->mechToken, value, vlen);
222-
conn->mechToken[vlen] = '\0';
223221
return 0;
224222
}
225223

fs/smb/server/auth.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,9 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
355355
if (blob_len < (u64)sess_key_off + sess_key_len)
356356
return -EINVAL;
357357

358+
if (sess_key_len > CIFS_KEY_SIZE)
359+
return -EINVAL;
360+
358361
ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL);
359362
if (!ctx_arc4)
360363
return -ENOMEM;
@@ -1029,11 +1032,15 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
10291032
{
10301033
struct scatterlist *sg;
10311034
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
1032-
int i, nr_entries[3] = {0}, total_entries = 0, sg_idx = 0;
1035+
int i, *nr_entries, total_entries = 0, sg_idx = 0;
10331036

10341037
if (!nvec)
10351038
return NULL;
10361039

1040+
nr_entries = kcalloc(nvec, sizeof(int), GFP_KERNEL);
1041+
if (!nr_entries)
1042+
return NULL;
1043+
10371044
for (i = 0; i < nvec - 1; i++) {
10381045
unsigned long kaddr = (unsigned long)iov[i + 1].iov_base;
10391046

@@ -1051,8 +1058,10 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
10511058
total_entries += 2;
10521059

10531060
sg = kmalloc_array(total_entries, sizeof(struct scatterlist), GFP_KERNEL);
1054-
if (!sg)
1061+
if (!sg) {
1062+
kfree(nr_entries);
10551063
return NULL;
1064+
}
10561065

10571066
sg_init_table(sg, total_entries);
10581067
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,
10861095
}
10871096
}
10881097
smb2_sg_set_buf(&sg[sg_idx], sign, SMB2_SIGNATURE_SIZE);
1098+
kfree(nr_entries);
10891099
return sg;
10901100
}
10911101

fs/smb/server/connection.c

Lines changed: 15 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -123,28 +123,22 @@ void ksmbd_conn_enqueue_request(struct ksmbd_work *work)
123123
}
124124
}
125125

126-
int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
126+
void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
127127
{
128128
struct ksmbd_conn *conn = work->conn;
129-
int ret = 1;
130129

131130
if (list_empty(&work->request_entry) &&
132131
list_empty(&work->async_request_entry))
133-
return 0;
132+
return;
134133

135-
if (!work->multiRsp)
136-
atomic_dec(&conn->req_running);
137-
if (!work->multiRsp) {
138-
spin_lock(&conn->request_lock);
139-
list_del_init(&work->request_entry);
140-
spin_unlock(&conn->request_lock);
141-
if (work->asynchronous)
142-
release_async_work(work);
143-
ret = 0;
144-
}
134+
atomic_dec(&conn->req_running);
135+
spin_lock(&conn->request_lock);
136+
list_del_init(&work->request_entry);
137+
spin_unlock(&conn->request_lock);
138+
if (work->asynchronous)
139+
release_async_work(work);
145140

146141
wake_up_all(&conn->req_running_q);
147-
return ret;
148142
}
149143

150144
void ksmbd_conn_lock(struct ksmbd_conn *conn)
@@ -193,41 +187,22 @@ void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id)
193187
int ksmbd_conn_write(struct ksmbd_work *work)
194188
{
195189
struct ksmbd_conn *conn = work->conn;
196-
size_t len = 0;
197190
int sent;
198-
struct kvec iov[3];
199-
int iov_idx = 0;
200191

201192
if (!work->response_buf) {
202193
pr_err("NULL response header\n");
203194
return -EINVAL;
204195
}
205196

206-
if (work->tr_buf) {
207-
iov[iov_idx] = (struct kvec) { work->tr_buf,
208-
sizeof(struct smb2_transform_hdr) + 4 };
209-
len += iov[iov_idx++].iov_len;
210-
}
211-
212-
if (work->aux_payload_sz) {
213-
iov[iov_idx] = (struct kvec) { work->response_buf, work->resp_hdr_sz };
214-
len += iov[iov_idx++].iov_len;
215-
iov[iov_idx] = (struct kvec) { work->aux_payload_buf, work->aux_payload_sz };
216-
len += iov[iov_idx++].iov_len;
217-
} else {
218-
if (work->tr_buf)
219-
iov[iov_idx].iov_len = work->resp_hdr_sz;
220-
else
221-
iov[iov_idx].iov_len = get_rfc1002_len(work->response_buf) + 4;
222-
iov[iov_idx].iov_base = work->response_buf;
223-
len += iov[iov_idx++].iov_len;
224-
}
197+
if (work->send_no_response)
198+
return 0;
225199

226200
ksmbd_conn_lock(conn);
227-
sent = conn->transport->ops->writev(conn->transport, &iov[0],
228-
iov_idx, len,
229-
work->need_invalidate_rkey,
230-
work->remote_key);
201+
sent = conn->transport->ops->writev(conn->transport, work->iov,
202+
work->iov_cnt,
203+
get_rfc1002_len(work->iov[0].iov_base) + 4,
204+
work->need_invalidate_rkey,
205+
work->remote_key);
231206
ksmbd_conn_unlock(conn);
232207

233208
if (sent < 0) {

fs/smb/server/connection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ int ksmbd_conn_rdma_write(struct ksmbd_conn *conn,
158158
struct smb2_buffer_desc_v1 *desc,
159159
unsigned int desc_len);
160160
void ksmbd_conn_enqueue_request(struct ksmbd_work *work);
161-
int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work);
161+
void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work);
162162
void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops);
163163
int ksmbd_conn_handler_loop(void *p);
164164
int ksmbd_conn_transport_init(void);

fs/smb/server/ksmbd_work.c

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,35 @@ struct ksmbd_work *ksmbd_alloc_work_struct(void)
2727
INIT_LIST_HEAD(&work->async_request_entry);
2828
INIT_LIST_HEAD(&work->fp_entry);
2929
INIT_LIST_HEAD(&work->interim_entry);
30+
INIT_LIST_HEAD(&work->aux_read_list);
31+
work->iov_alloc_cnt = 4;
32+
work->iov = kcalloc(work->iov_alloc_cnt, sizeof(struct kvec),
33+
GFP_KERNEL);
34+
if (!work->iov) {
35+
kmem_cache_free(work_cache, work);
36+
work = NULL;
37+
}
3038
}
3139
return work;
3240
}
3341

3442
void ksmbd_free_work_struct(struct ksmbd_work *work)
3543
{
44+
struct aux_read *ar, *tmp;
45+
3646
WARN_ON(work->saved_cred != NULL);
3747

3848
kvfree(work->response_buf);
39-
kvfree(work->aux_payload_buf);
49+
50+
list_for_each_entry_safe(ar, tmp, &work->aux_read_list, entry) {
51+
kvfree(ar->buf);
52+
list_del(&ar->entry);
53+
kfree(ar);
54+
}
55+
4056
kfree(work->tr_buf);
4157
kvfree(work->request_buf);
58+
kfree(work->iov);
4259
if (work->async_id)
4360
ksmbd_release_id(&work->conn->async_ida, work->async_id);
4461
kmem_cache_free(work_cache, work);
@@ -77,3 +94,77 @@ bool ksmbd_queue_work(struct ksmbd_work *work)
7794
{
7895
return queue_work(ksmbd_wq, &work->work);
7996
}
97+
98+
static int ksmbd_realloc_iov_pin(struct ksmbd_work *work, void *ib,
99+
unsigned int ib_len)
100+
{
101+
102+
if (work->iov_alloc_cnt <= work->iov_cnt) {
103+
struct kvec *new;
104+
105+
work->iov_alloc_cnt += 4;
106+
new = krealloc(work->iov,
107+
sizeof(struct kvec) * work->iov_alloc_cnt,
108+
GFP_KERNEL | __GFP_ZERO);
109+
if (!new)
110+
return -ENOMEM;
111+
work->iov = new;
112+
}
113+
114+
work->iov[++work->iov_idx].iov_base = ib;
115+
work->iov[work->iov_idx].iov_len = ib_len;
116+
work->iov_cnt++;
117+
118+
return 0;
119+
}
120+
121+
static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
122+
void *aux_buf, unsigned int aux_size)
123+
{
124+
/* Plus rfc_length size on first iov */
125+
if (!work->iov_idx) {
126+
work->iov[work->iov_idx].iov_base = work->response_buf;
127+
*(__be32 *)work->iov[0].iov_base = 0;
128+
work->iov[work->iov_idx].iov_len = 4;
129+
work->iov_cnt++;
130+
}
131+
132+
ksmbd_realloc_iov_pin(work, ib, len);
133+
inc_rfc1001_len(work->iov[0].iov_base, len);
134+
135+
if (aux_size) {
136+
struct aux_read *ar;
137+
138+
ksmbd_realloc_iov_pin(work, aux_buf, aux_size);
139+
inc_rfc1001_len(work->iov[0].iov_base, aux_size);
140+
141+
ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL);
142+
if (!ar)
143+
return -ENOMEM;
144+
145+
ar->buf = aux_buf;
146+
list_add(&ar->entry, &work->aux_read_list);
147+
}
148+
149+
return 0;
150+
}
151+
152+
int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len)
153+
{
154+
return __ksmbd_iov_pin_rsp(work, ib, len, NULL, 0);
155+
}
156+
157+
int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len,
158+
void *aux_buf, unsigned int aux_size)
159+
{
160+
return __ksmbd_iov_pin_rsp(work, ib, len, aux_buf, aux_size);
161+
}
162+
163+
int allocate_interim_rsp_buf(struct ksmbd_work *work)
164+
{
165+
work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL);
166+
if (!work->response_buf)
167+
return -ENOMEM;
168+
work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
169+
return 0;
170+
}

fs/smb/server/ksmbd_work.h

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ enum {
1919
KSMBD_WORK_CLOSED,
2020
};
2121

22+
struct aux_read {
23+
void *buf;
24+
struct list_head entry;
25+
};
26+
2227
/* one of these for every pending CIFS request at the connection */
2328
struct ksmbd_work {
2429
/* Server corresponding to this mid */
@@ -31,13 +36,19 @@ struct ksmbd_work {
3136
/* Response buffer */
3237
void *response_buf;
3338

34-
/* Read data buffer */
35-
void *aux_payload_buf;
39+
struct list_head aux_read_list;
40+
41+
struct kvec *iov;
42+
int iov_alloc_cnt;
43+
int iov_cnt;
44+
int iov_idx;
3645

3746
/* Next cmd hdr in compound req buf*/
3847
int next_smb2_rcv_hdr_off;
3948
/* Next cmd hdr in compound rsp buf*/
4049
int next_smb2_rsp_hdr_off;
50+
/* Current cmd hdr in compound rsp buf*/
51+
int curr_smb2_rsp_hdr_off;
4152

4253
/*
4354
* Current Local FID assigned compound response if SMB2 CREATE
@@ -53,16 +64,11 @@ struct ksmbd_work {
5364
unsigned int credits_granted;
5465

5566
/* response smb header size */
56-
unsigned int resp_hdr_sz;
5767
unsigned int response_sz;
58-
/* Read data count */
59-
unsigned int aux_payload_sz;
6068

6169
void *tr_buf;
6270

6371
unsigned char state;
64-
/* Multiple responses for one request e.g. SMB ECHO */
65-
bool multiRsp:1;
6672
/* No response for cancelled request */
6773
bool send_no_response:1;
6874
/* Request is encrypted */
@@ -95,6 +101,15 @@ static inline void *ksmbd_resp_buf_next(struct ksmbd_work *work)
95101
return work->response_buf + work->next_smb2_rsp_hdr_off + 4;
96102
}
97103

104+
/**
105+
* ksmbd_resp_buf_curr - Get current buffer on compound response.
106+
* @work: smb work containing response buffer
107+
*/
108+
static inline void *ksmbd_resp_buf_curr(struct ksmbd_work *work)
109+
{
110+
return work->response_buf + work->curr_smb2_rsp_hdr_off + 4;
111+
}
112+
98113
/**
99114
* ksmbd_req_buf_next - Get next buffer on compound request.
100115
* @work: smb work containing response buffer
@@ -113,5 +128,8 @@ int ksmbd_work_pool_init(void);
113128
int ksmbd_workqueue_init(void);
114129
void ksmbd_workqueue_destroy(void);
115130
bool ksmbd_queue_work(struct ksmbd_work *work);
116-
131+
int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len,
132+
void *aux_buf, unsigned int aux_size);
133+
int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len);
134+
int allocate_interim_rsp_buf(struct ksmbd_work *work);
117135
#endif /* __KSMBD_WORK_H__ */

fs/smb/server/mgmt/share_config.h

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,22 @@ struct ksmbd_share_config {
3434
#define KSMBD_SHARE_INVALID_UID ((__u16)-1)
3535
#define KSMBD_SHARE_INVALID_GID ((__u16)-1)
3636

37-
static inline int share_config_create_mode(struct ksmbd_share_config *share,
38-
umode_t posix_mode)
37+
static inline umode_t
38+
share_config_create_mode(struct ksmbd_share_config *share,
39+
umode_t posix_mode)
3940
{
40-
if (!share->force_create_mode) {
41-
if (!posix_mode)
42-
return share->create_mask;
43-
else
44-
return posix_mode & share->create_mask;
45-
}
46-
return share->force_create_mode & share->create_mask;
41+
umode_t mode = (posix_mode ?: (umode_t)-1) & share->create_mask;
42+
43+
return mode | share->force_create_mode;
4744
}
4845

49-
static inline int share_config_directory_mode(struct ksmbd_share_config *share,
50-
umode_t posix_mode)
46+
static inline umode_t
47+
share_config_directory_mode(struct ksmbd_share_config *share,
48+
umode_t posix_mode)
5149
{
52-
if (!share->force_directory_mode) {
53-
if (!posix_mode)
54-
return share->directory_mask;
55-
else
56-
return posix_mode & share->directory_mask;
57-
}
50+
umode_t mode = (posix_mode ?: (umode_t)-1) & share->directory_mask;
5851

59-
return share->force_directory_mode & share->directory_mask;
52+
return mode | share->force_directory_mode;
6053
}
6154

6255
static inline int test_share_config_flag(struct ksmbd_share_config *share,

0 commit comments

Comments
 (0)