mirror of https://gitee.com/openkylin/linux.git
tls: fix currently broken MSG_PEEK behavior
In kTLS MSG_PEEK behavior is currently failing, strace example: [pid 2430] socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3 [pid 2430] socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 4 [pid 2430] bind(4, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 [pid 2430] listen(4, 10) = 0 [pid 2430] getsockname(4, {sa_family=AF_INET, sin_port=htons(38855), sin_addr=inet_addr("0.0.0.0")}, [16]) = 0 [pid 2430] connect(3, {sa_family=AF_INET, sin_port=htons(38855), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 [pid 2430] setsockopt(3, SOL_TCP, 0x1f /* TCP_??? */, [7564404], 4) = 0 [pid 2430] setsockopt(3, 0x11a /* SOL_?? */, 1, "\3\0033\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 40) = 0 [pid 2430] accept(4, {sa_family=AF_INET, sin_port=htons(49636), sin_addr=inet_addr("127.0.0.1")}, [16]) = 5 [pid 2430] setsockopt(5, SOL_TCP, 0x1f /* TCP_??? */, [7564404], 4) = 0 [pid 2430] setsockopt(5, 0x11a /* SOL_?? */, 2, "\3\0033\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 40) = 0 [pid 2430] close(4) = 0 [pid 2430] sendto(3, "test_read_peek", 14, 0, NULL, 0) = 14 [pid 2430] sendto(3, "_mult_recs\0", 11, 0, NULL, 0) = 11 [pid 2430] recvfrom(5, "test_read_peektest_read_peektest"..., 64, MSG_PEEK, NULL, NULL) = 64 As can be seen from strace, there are two TLS records sent, i) 'test_read_peek' and ii) '_mult_recs\0' where we end up peeking 'test_read_peektest_read_peektest'. This is clearly wrong, and what happens is that given peek cannot call into tls_sw_advance_skb() to unpause strparser and proceed with the next skb, we end up looping over the current one, copying the 'test_read_peek' over and over into the user provided buffer. Here, we can only peek into the currently held skb (current, full TLS record) as otherwise we would end up having to hold all the original skb(s) (depending on the peek depth) in a separate queue when unpausing strparser to process next records, minimally intrusive is to return only up to the current record's size (which likely was whatc46234ebb4
("tls: RX path for ktls") originally intended as well). Thus, after patch we properly peek the first record: [pid 2046] wait4(2075, <unfinished ...> [pid 2075] socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3 [pid 2075] socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 4 [pid 2075] bind(4, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 [pid 2075] listen(4, 10) = 0 [pid 2075] getsockname(4, {sa_family=AF_INET, sin_port=htons(55115), sin_addr=inet_addr("0.0.0.0")}, [16]) = 0 [pid 2075] connect(3, {sa_family=AF_INET, sin_port=htons(55115), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 [pid 2075] setsockopt(3, SOL_TCP, 0x1f /* TCP_??? */, [7564404], 4) = 0 [pid 2075] setsockopt(3, 0x11a /* SOL_?? */, 1, "\3\0033\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 40) = 0 [pid 2075] accept(4, {sa_family=AF_INET, sin_port=htons(45732), sin_addr=inet_addr("127.0.0.1")}, [16]) = 5 [pid 2075] setsockopt(5, SOL_TCP, 0x1f /* TCP_??? */, [7564404], 4) = 0 [pid 2075] setsockopt(5, 0x11a /* SOL_?? */, 2, "\3\0033\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 40) = 0 [pid 2075] close(4) = 0 [pid 2075] sendto(3, "test_read_peek", 14, 0, NULL, 0) = 14 [pid 2075] sendto(3, "_mult_recs\0", 11, 0, NULL, 0) = 11 [pid 2075] recvfrom(5, "test_read_peek", 64, MSG_PEEK, NULL, NULL) = 14 Fixes:c46234ebb4
("tls: RX path for ktls") Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
aa079bd050
commit
50c6b58a81
|
@ -931,7 +931,15 @@ int tls_sw_recvmsg(struct sock *sk,
|
|||
if (control != TLS_RECORD_TYPE_DATA)
|
||||
goto recv_end;
|
||||
}
|
||||
} else {
|
||||
/* MSG_PEEK right now cannot look beyond current skb
|
||||
* from strparser, meaning we cannot advance skb here
|
||||
* and thus unpause strparser since we'd loose original
|
||||
* one.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we have a new message from strparser, continue now. */
|
||||
if (copied >= target && !ctx->recv_pkt)
|
||||
break;
|
||||
|
|
|
@ -502,6 +502,55 @@ TEST_F(tls, recv_peek_multiple)
|
|||
EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, recv_peek_multiple_records)
|
||||
{
|
||||
char const *test_str = "test_read_peek_mult_recs";
|
||||
char const *test_str_first = "test_read_peek";
|
||||
char const *test_str_second = "_mult_recs";
|
||||
int len;
|
||||
char buf[64];
|
||||
|
||||
len = strlen(test_str_first);
|
||||
EXPECT_EQ(send(self->fd, test_str_first, len, 0), len);
|
||||
|
||||
len = strlen(test_str_second) + 1;
|
||||
EXPECT_EQ(send(self->fd, test_str_second, len, 0), len);
|
||||
|
||||
len = sizeof(buf);
|
||||
memset(buf, 0, len);
|
||||
EXPECT_NE(recv(self->cfd, buf, len, MSG_PEEK), -1);
|
||||
|
||||
/* MSG_PEEK can only peek into the current record. */
|
||||
len = strlen(test_str_first) + 1;
|
||||
EXPECT_EQ(memcmp(test_str_first, buf, len), 0);
|
||||
|
||||
len = sizeof(buf);
|
||||
memset(buf, 0, len);
|
||||
EXPECT_NE(recv(self->cfd, buf, len, 0), -1);
|
||||
|
||||
/* Non-MSG_PEEK will advance strparser (and therefore record)
|
||||
* however.
|
||||
*/
|
||||
len = strlen(test_str) + 1;
|
||||
EXPECT_EQ(memcmp(test_str, buf, len), 0);
|
||||
|
||||
/* MSG_MORE will hold current record open, so later MSG_PEEK
|
||||
* will see everything.
|
||||
*/
|
||||
len = strlen(test_str_first);
|
||||
EXPECT_EQ(send(self->fd, test_str_first, len, MSG_MORE), len);
|
||||
|
||||
len = strlen(test_str_second) + 1;
|
||||
EXPECT_EQ(send(self->fd, test_str_second, len, 0), len);
|
||||
|
||||
len = sizeof(buf);
|
||||
memset(buf, 0, len);
|
||||
EXPECT_NE(recv(self->cfd, buf, len, MSG_PEEK), -1);
|
||||
|
||||
len = strlen(test_str) + 1;
|
||||
EXPECT_EQ(memcmp(test_str, buf, len), 0);
|
||||
}
|
||||
|
||||
TEST_F(tls, pollin)
|
||||
{
|
||||
char const *test_str = "test_poll";
|
||||
|
|
Loading…
Reference in New Issue