Skip to content

Commit 1838cf8

Browse files
Guangguan WangNipaLocal
Guangguan Wang
authored and
NipaLocal
committed
net/smc: fix data error when recvmsg with MSG_PEEK flag
When recvmsg with MSG_PEEK flag, the data will be copied to user's buffer without advancing consume cursor and without reducing the length of rx available data. Once the expected peek length is larger than the value of bytes_to_rcv, in the loop of do while in smc_rx_recvmsg, the first loop will copy bytes_to_rcv bytes of data from the position local_tx_ctrl.cons, the second loop will copy the min(bytes_to_rcv, read_remaining) bytes from the position local_tx_ctrl.cons again because of the lacking of process with advancing consume cursor and reducing the length of available data. So do the subsequent loops. The data copied in the second loop and the subsequent loops will result in data error, as it should not be copied if no more data arrives and it should be copied from the position advancing bytes_to_rcv bytes from the local_tx_ctrl.cons if more data arrives. This issue can be reproduce by the following python script: server.py: import socket import time server_ip = '0.0.0.0' server_port = 12346 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind((server_ip, server_port)) server_socket.listen(1) print('Server is running and listening for connections...') conn, addr = server_socket.accept() print('Connected by', addr) while True: data = conn.recv(1024) if not data: break print('Received request:', data.decode()) conn.sendall(b'Hello, client!\n') time.sleep(5) conn.sendall(b'Hello, again!\n') conn.close() client.py: import socket server_ip = '<server ip>' server_port = 12346 resp=b'Hello, client!\nHello, again!\n' client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((server_ip, server_port)) request = 'Hello, server!' client_socket.sendall(request.encode()) peek_data = client_socket.recv(len(resp), socket.MSG_PEEK | socket.MSG_WAITALL) print('Peeked data:', peek_data.decode()) client_socket.close() Fixes: 952310c ("smc: receive data from RMBE") Reported-by: D. Wythe <[email protected]> Signed-off-by: Guangguan Wang <[email protected]> Signed-off-by: NipaLocal <nipa@local>
1 parent 9e963d5 commit 1838cf8

File tree

3 files changed

+26
-21
lines changed

3 files changed

+26
-21
lines changed

net/smc/af_smc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2741,7 +2741,7 @@ int smc_accept(struct socket *sock, struct socket *new_sock,
27412741
release_sock(clcsk);
27422742
} else if (!atomic_read(&smc_sk(nsk)->conn.bytes_to_rcv)) {
27432743
lock_sock(nsk);
2744-
smc_rx_wait(smc_sk(nsk), &timeo, smc_rx_data_available);
2744+
smc_rx_wait(smc_sk(nsk), &timeo, 0, smc_rx_data_available);
27452745
release_sock(nsk);
27462746
}
27472747
}

net/smc/smc_rx.c

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -238,22 +238,23 @@ static int smc_rx_splice(struct pipe_inode_info *pipe, char *src, size_t len,
238238
return -ENOMEM;
239239
}
240240

241-
static int smc_rx_data_available_and_no_splice_pend(struct smc_connection *conn)
241+
static int smc_rx_data_available_and_no_splice_pend(struct smc_connection *conn, size_t peeked)
242242
{
243-
return atomic_read(&conn->bytes_to_rcv) &&
243+
return smc_rx_data_available(conn, peeked) &&
244244
!atomic_read(&conn->splice_pending);
245245
}
246246

247247
/* blocks rcvbuf consumer until >=len bytes available or timeout or interrupted
248248
* @smc smc socket
249249
* @timeo pointer to max seconds to wait, pointer to value 0 for no timeout
250+
* @peeked number of bytes already peeked
250251
* @fcrit add'l criterion to evaluate as function pointer
251252
* Returns:
252253
* 1 if at least 1 byte available in rcvbuf or if socket error/shutdown.
253254
* 0 otherwise (nothing in rcvbuf nor timeout, e.g. interrupted).
254255
*/
255-
int smc_rx_wait(struct smc_sock *smc, long *timeo,
256-
int (*fcrit)(struct smc_connection *conn))
256+
int smc_rx_wait(struct smc_sock *smc, long *timeo, size_t peeked,
257+
int (*fcrit)(struct smc_connection *conn, size_t baseline))
257258
{
258259
DEFINE_WAIT_FUNC(wait, woken_wake_function);
259260
struct smc_connection *conn = &smc->conn;
@@ -262,7 +263,7 @@ int smc_rx_wait(struct smc_sock *smc, long *timeo,
262263
struct sock *sk = &smc->sk;
263264
int rc;
264265

265-
if (fcrit(conn))
266+
if (fcrit(conn, peeked))
266267
return 1;
267268
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
268269
add_wait_queue(sk_sleep(sk), &wait);
@@ -271,7 +272,7 @@ int smc_rx_wait(struct smc_sock *smc, long *timeo,
271272
cflags->peer_conn_abort ||
272273
READ_ONCE(sk->sk_shutdown) & RCV_SHUTDOWN ||
273274
conn->killed ||
274-
fcrit(conn),
275+
fcrit(conn, peeked),
275276
&wait);
276277
remove_wait_queue(sk_sleep(sk), &wait);
277278
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
@@ -322,11 +323,11 @@ static int smc_rx_recv_urg(struct smc_sock *smc, struct msghdr *msg, int len,
322323
return -EAGAIN;
323324
}
324325

325-
static bool smc_rx_recvmsg_data_available(struct smc_sock *smc)
326+
static bool smc_rx_recvmsg_data_available(struct smc_sock *smc, size_t peeked)
326327
{
327328
struct smc_connection *conn = &smc->conn;
328329

329-
if (smc_rx_data_available(conn))
330+
if (smc_rx_data_available(conn, peeked))
330331
return true;
331332
else if (conn->urg_state == SMC_URG_VALID)
332333
/* we received a single urgent Byte - skip */
@@ -344,10 +345,10 @@ static bool smc_rx_recvmsg_data_available(struct smc_sock *smc)
344345
int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg,
345346
struct pipe_inode_info *pipe, size_t len, int flags)
346347
{
347-
size_t copylen, read_done = 0, read_remaining = len;
348+
size_t copylen, read_done = 0, read_remaining = len, peeked_bytes = 0;
348349
size_t chunk_len, chunk_off, chunk_len_sum;
349350
struct smc_connection *conn = &smc->conn;
350-
int (*func)(struct smc_connection *conn);
351+
int (*func)(struct smc_connection *conn, size_t baseline);
351352
union smc_host_cursor cons;
352353
int readable, chunk;
353354
char *rcvbuf_base;
@@ -384,14 +385,14 @@ int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg,
384385
if (conn->killed)
385386
break;
386387

387-
if (smc_rx_recvmsg_data_available(smc))
388+
if (smc_rx_recvmsg_data_available(smc, peeked_bytes))
388389
goto copy;
389390

390391
if (sk->sk_shutdown & RCV_SHUTDOWN) {
391392
/* smc_cdc_msg_recv_action() could have run after
392393
* above smc_rx_recvmsg_data_available()
393394
*/
394-
if (smc_rx_recvmsg_data_available(smc))
395+
if (smc_rx_recvmsg_data_available(smc, peeked_bytes))
395396
goto copy;
396397
break;
397398
}
@@ -425,26 +426,28 @@ int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg,
425426
}
426427
}
427428

428-
if (!smc_rx_data_available(conn)) {
429-
smc_rx_wait(smc, &timeo, smc_rx_data_available);
429+
if (!smc_rx_data_available(conn, peeked_bytes)) {
430+
smc_rx_wait(smc, &timeo, peeked_bytes, smc_rx_data_available);
430431
continue;
431432
}
432433

433434
copy:
434435
/* initialize variables for 1st iteration of subsequent loop */
435436
/* could be just 1 byte, even after waiting on data above */
436-
readable = atomic_read(&conn->bytes_to_rcv);
437+
readable = smc_rx_data_available(conn, peeked_bytes);
437438
splbytes = atomic_read(&conn->splice_pending);
438439
if (!readable || (msg && splbytes)) {
439440
if (splbytes)
440441
func = smc_rx_data_available_and_no_splice_pend;
441442
else
442443
func = smc_rx_data_available;
443-
smc_rx_wait(smc, &timeo, func);
444+
smc_rx_wait(smc, &timeo, peeked_bytes, func);
444445
continue;
445446
}
446447

447448
smc_curs_copy(&cons, &conn->local_tx_ctrl.cons, conn);
449+
if ((flags & MSG_PEEK) && peeked_bytes)
450+
smc_curs_add(conn->rmb_desc->len, &cons, peeked_bytes);
448451
/* subsequent splice() calls pick up where previous left */
449452
if (splbytes)
450453
smc_curs_add(conn->rmb_desc->len, &cons, splbytes);
@@ -480,6 +483,8 @@ int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg,
480483
}
481484
read_remaining -= chunk_len;
482485
read_done += chunk_len;
486+
if (flags & MSG_PEEK)
487+
peeked_bytes += chunk_len;
483488

484489
if (chunk_len_sum == copylen)
485490
break; /* either on 1st or 2nd iteration */

net/smc/smc_rx.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ void smc_rx_init(struct smc_sock *smc);
2121

2222
int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg,
2323
struct pipe_inode_info *pipe, size_t len, int flags);
24-
int smc_rx_wait(struct smc_sock *smc, long *timeo,
25-
int (*fcrit)(struct smc_connection *conn));
26-
static inline int smc_rx_data_available(struct smc_connection *conn)
24+
int smc_rx_wait(struct smc_sock *smc, long *timeo, size_t peeked,
25+
int (*fcrit)(struct smc_connection *conn, size_t baseline));
26+
static inline int smc_rx_data_available(struct smc_connection *conn, size_t peeked)
2727
{
28-
return atomic_read(&conn->bytes_to_rcv);
28+
return atomic_read(&conn->bytes_to_rcv) - peeked;
2929
}
3030

3131
#endif /* SMC_RX_H */

0 commit comments

Comments
 (0)