Skip to content

Commit 58325d8

Browse files
author
Mete Durlu
committed
net/smc: fix data error when recvmsg with MSG_PEEK flag
JIRA: https://issues.redhat.com/browse/RHEL-99989 commit a4b6539 Author: Guangguan Wang <guangguan.wang@linux.alibaba.com> Date: Sat Jan 4 22:32:01 2025 +0800 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 <alibuda@linux.alibaba.com> Signed-off-by: Guangguan Wang <guangguan.wang@linux.alibaba.com> Link: https://patch.msgid.link/20250104143201.35529-1-guangguan.wang@linux.alibaba.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Mahanta Jambigi <mjambigi@linux.ibm.com> Signed-off-by: Mete Durlu <mdurlu@redhat.com>
1 parent 6c1ea19 commit 58325d8

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
@@ -2730,7 +2730,7 @@ int smc_accept(struct socket *sock, struct socket *new_sock,
27302730
release_sock(clcsk);
27312731
} else if (!atomic_read(&smc_sk(nsk)->conn.bytes_to_rcv)) {
27322732
lock_sock(nsk);
2733-
smc_rx_wait(smc_sk(nsk), &timeo, smc_rx_data_available);
2733+
smc_rx_wait(smc_sk(nsk), &timeo, 0, smc_rx_data_available);
27342734
release_sock(nsk);
27352735
}
27362736
}

net/smc/smc_rx.c

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

240-
static int smc_rx_data_available_and_no_splice_pend(struct smc_connection *conn)
240+
static int smc_rx_data_available_and_no_splice_pend(struct smc_connection *conn, size_t peeked)
241241
{
242-
return atomic_read(&conn->bytes_to_rcv) &&
242+
return smc_rx_data_available(conn, peeked) &&
243243
!atomic_read(&conn->splice_pending);
244244
}
245245

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

264-
if (fcrit(conn))
265+
if (fcrit(conn, peeked))
265266
return 1;
266267
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
267268
add_wait_queue(sk_sleep(sk), &wait);
@@ -270,7 +271,7 @@ int smc_rx_wait(struct smc_sock *smc, long *timeo,
270271
cflags->peer_conn_abort ||
271272
sk->sk_shutdown & RCV_SHUTDOWN ||
272273
conn->killed ||
273-
fcrit(conn),
274+
fcrit(conn, peeked),
274275
&wait);
275276
remove_wait_queue(sk_sleep(sk), &wait);
276277
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
@@ -321,11 +322,11 @@ static int smc_rx_recv_urg(struct smc_sock *smc, struct msghdr *msg, int len,
321322
return -EAGAIN;
322323
}
323324

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

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

386-
if (smc_rx_recvmsg_data_available(smc))
387+
if (smc_rx_recvmsg_data_available(smc, peeked_bytes))
387388
goto copy;
388389

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

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

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

446447
smc_curs_copy(&cons, &conn->local_tx_ctrl.cons, conn);
448+
if ((flags & MSG_PEEK) && peeked_bytes)
449+
smc_curs_add(conn->rmb_desc->len, &cons, peeked_bytes);
447450
/* subsequent splice() calls pick up where previous left */
448451
if (splbytes)
449452
smc_curs_add(conn->rmb_desc->len, &cons, splbytes);
@@ -479,6 +482,8 @@ int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg,
479482
}
480483
read_remaining -= chunk_len;
481484
read_done += chunk_len;
485+
if (flags & MSG_PEEK)
486+
peeked_bytes += chunk_len;
482487

483488
if (chunk_len_sum == copylen)
484489
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)