Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag '6.17-rc6-ksmbd-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

- Two fixes for remaining_data_length and offset checks in receive path

- Don't go over max SGEs which caused smbdirect send to fail (and
trigger disconnect)

* tag '6.17-rc6-ksmbd-fixes' of git://git.samba.org/ksmbd:
ksmbd: smbdirect: verify remaining_data_length respects max_fragmented_recv_size
ksmbd: smbdirect: validate data_offset and data_length field of smb_direct_data_transfer
smb: server: let smb_direct_writev() respect SMB_DIRECT_MAX_SEND_SGES

+126 -59
+126 -59
fs/smb/server/transport_rdma.c
··· 554 554 case SMB_DIRECT_MSG_DATA_TRANSFER: { 555 555 struct smb_direct_data_transfer *data_transfer = 556 556 (struct smb_direct_data_transfer *)recvmsg->packet; 557 - unsigned int data_length; 557 + u32 remaining_data_length, data_offset, data_length; 558 558 int avail_recvmsg_count, receive_credits; 559 559 560 560 if (wc->byte_len < ··· 564 564 return; 565 565 } 566 566 567 + remaining_data_length = le32_to_cpu(data_transfer->remaining_data_length); 567 568 data_length = le32_to_cpu(data_transfer->data_length); 568 - if (data_length) { 569 - if (wc->byte_len < sizeof(struct smb_direct_data_transfer) + 570 - (u64)data_length) { 571 - put_recvmsg(t, recvmsg); 572 - smb_direct_disconnect_rdma_connection(t); 573 - return; 574 - } 569 + data_offset = le32_to_cpu(data_transfer->data_offset); 570 + if (wc->byte_len < data_offset || 571 + wc->byte_len < (u64)data_offset + data_length) { 572 + put_recvmsg(t, recvmsg); 573 + smb_direct_disconnect_rdma_connection(t); 574 + return; 575 + } 576 + if (remaining_data_length > t->max_fragmented_recv_size || 577 + data_length > t->max_fragmented_recv_size || 578 + (u64)remaining_data_length + (u64)data_length > 579 + (u64)t->max_fragmented_recv_size) { 580 + put_recvmsg(t, recvmsg); 581 + smb_direct_disconnect_rdma_connection(t); 582 + return; 583 + } 575 584 585 + if (data_length) { 576 586 if (t->full_packet_received) 577 587 recvmsg->first_segment = true; 578 588 ··· 1219 1209 bool need_invalidate, unsigned int remote_key) 1220 1210 { 1221 1211 struct smb_direct_transport *st = smb_trans_direct_transfort(t); 1222 - int remaining_data_length; 1223 - int start, i, j; 1224 - int max_iov_size = st->max_send_size - 1212 + size_t remaining_data_length; 1213 + size_t iov_idx; 1214 + size_t iov_ofs; 1215 + size_t max_iov_size = st->max_send_size - 1225 1216 sizeof(struct smb_direct_data_transfer); 1226 1217 int ret; 1227 - struct kvec vec; 1228 1218 struct smb_direct_send_ctx send_ctx; 1219 + int error = 0; 1229 1220 1230 1221 if (st->status != SMB_DIRECT_CS_CONNECTED) 1231 1222 return -ENOTCONN; 1232 1223 1233 1224 //FIXME: skip RFC1002 header.. 1225 + if (WARN_ON_ONCE(niovs <= 1 || iov[0].iov_len != 4)) 1226 + return -EINVAL; 1234 1227 buflen -= 4; 1228 + iov_idx = 1; 1229 + iov_ofs = 0; 1235 1230 1236 1231 remaining_data_length = buflen; 1237 1232 ksmbd_debug(RDMA, "Sending smb (RDMA): smb_len=%u\n", buflen); 1238 1233 1239 1234 smb_direct_send_ctx_init(st, &send_ctx, need_invalidate, remote_key); 1240 - start = i = 1; 1241 - buflen = 0; 1242 - while (true) { 1243 - buflen += iov[i].iov_len; 1244 - if (buflen > max_iov_size) { 1245 - if (i > start) { 1246 - remaining_data_length -= 1247 - (buflen - iov[i].iov_len); 1248 - ret = smb_direct_post_send_data(st, &send_ctx, 1249 - &iov[start], i - start, 1250 - remaining_data_length); 1251 - if (ret) 1252 - goto done; 1253 - } else { 1254 - /* iov[start] is too big, break it */ 1255 - int nvec = (buflen + max_iov_size - 1) / 1256 - max_iov_size; 1235 + while (remaining_data_length) { 1236 + struct kvec vecs[SMB_DIRECT_MAX_SEND_SGES - 1]; /* minus smbdirect hdr */ 1237 + size_t possible_bytes = max_iov_size; 1238 + size_t possible_vecs; 1239 + size_t bytes = 0; 1240 + size_t nvecs = 0; 1257 1241 1258 - for (j = 0; j < nvec; j++) { 1259 - vec.iov_base = 1260 - (char *)iov[start].iov_base + 1261 - j * max_iov_size; 1262 - vec.iov_len = 1263 - min_t(int, max_iov_size, 1264 - buflen - max_iov_size * j); 1265 - remaining_data_length -= vec.iov_len; 1266 - ret = smb_direct_post_send_data(st, &send_ctx, &vec, 1, 1267 - remaining_data_length); 1268 - if (ret) 1269 - goto done; 1270 - } 1271 - i++; 1272 - if (i == niovs) 1273 - break; 1274 - } 1275 - start = i; 1276 - buflen = 0; 1277 - } else { 1278 - i++; 1279 - if (i == niovs) { 1280 - /* send out all remaining vecs */ 1281 - remaining_data_length -= buflen; 1282 - ret = smb_direct_post_send_data(st, &send_ctx, 1283 - &iov[start], i - start, 1284 - remaining_data_length); 1285 - if (ret) 1242 + /* 1243 + * For the last message remaining_data_length should be 1244 + * have been 0 already! 1245 + */ 1246 + if (WARN_ON_ONCE(iov_idx >= niovs)) { 1247 + error = -EINVAL; 1248 + goto done; 1249 + } 1250 + 1251 + /* 1252 + * We have 2 factors which limit the arguments we pass 1253 + * to smb_direct_post_send_data(): 1254 + * 1255 + * 1. The number of supported sges for the send, 1256 + * while one is reserved for the smbdirect header. 1257 + * And we currently need one SGE per page. 1258 + * 2. The number of negotiated payload bytes per send. 1259 + */ 1260 + possible_vecs = min_t(size_t, ARRAY_SIZE(vecs), niovs - iov_idx); 1261 + 1262 + while (iov_idx < niovs && possible_vecs && possible_bytes) { 1263 + struct kvec *v = &vecs[nvecs]; 1264 + int page_count; 1265 + 1266 + v->iov_base = ((u8 *)iov[iov_idx].iov_base) + iov_ofs; 1267 + v->iov_len = min_t(size_t, 1268 + iov[iov_idx].iov_len - iov_ofs, 1269 + possible_bytes); 1270 + page_count = get_buf_page_count(v->iov_base, v->iov_len); 1271 + if (page_count > possible_vecs) { 1272 + /* 1273 + * If the number of pages in the buffer 1274 + * is to much (because we currently require 1275 + * one SGE per page), we need to limit the 1276 + * length. 1277 + * 1278 + * We know possible_vecs is at least 1, 1279 + * so we always keep the first page. 1280 + * 1281 + * We need to calculate the number extra 1282 + * pages (epages) we can also keep. 1283 + * 1284 + * We calculate the number of bytes in the 1285 + * first page (fplen), this should never be 1286 + * larger than v->iov_len because page_count is 1287 + * at least 2, but adding a limitation feels 1288 + * better. 1289 + * 1290 + * Then we calculate the number of bytes (elen) 1291 + * we can keep for the extra pages. 1292 + */ 1293 + size_t epages = possible_vecs - 1; 1294 + size_t fpofs = offset_in_page(v->iov_base); 1295 + size_t fplen = min_t(size_t, PAGE_SIZE - fpofs, v->iov_len); 1296 + size_t elen = min_t(size_t, v->iov_len - fplen, epages*PAGE_SIZE); 1297 + 1298 + v->iov_len = fplen + elen; 1299 + page_count = get_buf_page_count(v->iov_base, v->iov_len); 1300 + if (WARN_ON_ONCE(page_count > possible_vecs)) { 1301 + /* 1302 + * Something went wrong in the above 1303 + * logic... 1304 + */ 1305 + error = -EINVAL; 1286 1306 goto done; 1287 - break; 1307 + } 1288 1308 } 1309 + possible_vecs -= page_count; 1310 + nvecs += 1; 1311 + possible_bytes -= v->iov_len; 1312 + bytes += v->iov_len; 1313 + 1314 + iov_ofs += v->iov_len; 1315 + if (iov_ofs >= iov[iov_idx].iov_len) { 1316 + iov_idx += 1; 1317 + iov_ofs = 0; 1318 + } 1319 + } 1320 + 1321 + remaining_data_length -= bytes; 1322 + 1323 + ret = smb_direct_post_send_data(st, &send_ctx, 1324 + vecs, nvecs, 1325 + remaining_data_length); 1326 + if (unlikely(ret)) { 1327 + error = ret; 1328 + goto done; 1289 1329 } 1290 1330 } 1291 1331 1292 1332 done: 1293 1333 ret = smb_direct_flush_send_list(st, &send_ctx, true); 1334 + if (unlikely(!ret && error)) 1335 + ret = error; 1294 1336 1295 1337 /* 1296 1338 * As an optimization, we don't wait for individual I/O to finish ··· 1806 1744 return -EINVAL; 1807 1745 } 1808 1746 1747 + if (device->attrs.max_send_sge < SMB_DIRECT_MAX_SEND_SGES) { 1748 + pr_err("warning: device max_send_sge = %d too small\n", 1749 + device->attrs.max_send_sge); 1750 + return -EINVAL; 1751 + } 1809 1752 if (device->attrs.max_recv_sge < SMB_DIRECT_MAX_RECV_SGES) { 1810 1753 pr_err("warning: device max_recv_sge = %d too small\n", 1811 1754 device->attrs.max_recv_sge); ··· 1834 1767 1835 1768 cap->max_send_wr = max_send_wrs; 1836 1769 cap->max_recv_wr = t->recv_credit_max; 1837 - cap->max_send_sge = max_sge_per_wr; 1770 + cap->max_send_sge = SMB_DIRECT_MAX_SEND_SGES; 1838 1771 cap->max_recv_sge = SMB_DIRECT_MAX_RECV_SGES; 1839 1772 cap->max_inline_data = 0; 1840 1773 cap->max_rdma_ctxs = t->max_rw_credits;