Skip to content

Commit b26eeb3

Browse files
committed
net/tls: allow limiting maximum record size
During a handshake, an endpoint may specify a maximum record size limit. Currently, the kernel defaults to TLS_MAX_PAYLOAD_SIZE (16KB) for the maximum record size. Meaning that, the outgoing records from the kernel can exceed a lower size negotiated during the handshake. In such a case, the TLS endpoint must send a fatal "record_overflow" alert [1], and thus the record is discarded. Upcoming Western Digital NVMe-TCP hardware controllers implement TLS support. For these devices, supporting TLS record size negotiation is necessary because the maximum TLS record size supported by the controller is less than the default 16KB currently used by the kernel. This patch adds support for retrieving the negotiated record size limit during a handshake, and enforcing it at the TLS layer such that outgoing records are no larger than the size negotiated. This patch depends on the respective userspace support in tlshd [2] and GnuTLS [3]. [1] https://www.rfc-editor.org/rfc/rfc8449 [2] oracle/ktls-utils#112 [3] https://gitlab.com/gnutls/gnutls/-/merge_requests/2005 Signed-off-by: Wilfred Mallawa <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]>
1 parent b320789 commit b26eeb3

File tree

6 files changed

+42
-4
lines changed

6 files changed

+42
-4
lines changed

Documentation/netlink/specs/handshake.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ attribute-sets:
8787
name: remote-auth
8888
type: u32
8989
multi-attr: true
90+
-
91+
name: record-size-limit
92+
type: u32
9093

9194
operations:
9295
list:

include/net/tls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ struct tls_context {
250250
*/
251251
unsigned long flags;
252252

253+
u32 tls_record_size_limit;
254+
253255
/* cache cold stuff */
254256
struct proto *sk_proto;
255257
struct sock *sk;

include/uapi/linux/handshake.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ enum {
5555
HANDSHAKE_A_DONE_STATUS = 1,
5656
HANDSHAKE_A_DONE_SOCKFD,
5757
HANDSHAKE_A_DONE_REMOTE_AUTH,
58+
HANDSHAKE_A_DONE_RECORD_SIZE_LIMIT,
5859

5960
__HANDSHAKE_A_DONE_MAX,
6061
HANDSHAKE_A_DONE_MAX = (__HANDSHAKE_A_DONE_MAX - 1)

net/handshake/genl.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ static const struct nla_policy handshake_accept_nl_policy[HANDSHAKE_A_ACCEPT_HAN
1616
};
1717

1818
/* HANDSHAKE_CMD_DONE - do */
19-
static const struct nla_policy handshake_done_nl_policy[HANDSHAKE_A_DONE_REMOTE_AUTH + 1] = {
19+
static const struct nla_policy handshake_done_nl_policy[__HANDSHAKE_A_DONE_MAX] = {
2020
[HANDSHAKE_A_DONE_STATUS] = { .type = NLA_U32, },
2121
[HANDSHAKE_A_DONE_SOCKFD] = { .type = NLA_S32, },
2222
[HANDSHAKE_A_DONE_REMOTE_AUTH] = { .type = NLA_U32, },
23+
[HANDSHAKE_A_DONE_RECORD_SIZE_LIMIT] = { .type = NLA_U32, },
2324
};
2425

2526
/* Ops table for handshake */
@@ -35,7 +36,7 @@ static const struct genl_split_ops handshake_nl_ops[] = {
3536
.cmd = HANDSHAKE_CMD_DONE,
3637
.doit = handshake_nl_done_doit,
3738
.policy = handshake_done_nl_policy,
38-
.maxattr = HANDSHAKE_A_DONE_REMOTE_AUTH,
39+
.maxattr = HANDSHAKE_A_DONE_MAX,
3940
.flags = GENL_CMD_CAP_DO,
4041
},
4142
};

net/handshake/tlshd.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <net/handshake.h>
2020
#include <net/genetlink.h>
2121
#include <net/tls_prot.h>
22+
#include <net/tls.h>
2223

2324
#include <uapi/linux/keyctl.h>
2425
#include <uapi/linux/handshake.h>
@@ -37,6 +38,8 @@ struct tls_handshake_req {
3738
key_serial_t th_certificate;
3839
key_serial_t th_privkey;
3940

41+
struct socket *th_sock;
42+
4043
unsigned int th_num_peerids;
4144
key_serial_t th_peerid[5];
4245
};
@@ -52,6 +55,7 @@ tls_handshake_req_init(struct handshake_req *req,
5255
treq->th_consumer_data = args->ta_data;
5356
treq->th_peername = args->ta_peername;
5457
treq->th_keyring = args->ta_keyring;
58+
treq->th_sock = args->ta_sock;
5559
treq->th_num_peerids = 0;
5660
treq->th_certificate = TLS_NO_CERT;
5761
treq->th_privkey = TLS_NO_PRIVKEY;
@@ -85,6 +89,27 @@ static void tls_handshake_remote_peerids(struct tls_handshake_req *treq,
8589
}
8690
}
8791

92+
static void tls_handshake_record_size(struct tls_handshake_req *treq,
93+
struct genl_info *info)
94+
{
95+
struct tls_context *tls_ctx;
96+
struct nlattr *head = nlmsg_attrdata(info->nlhdr, GENL_HDRLEN);
97+
struct nlattr *nla;
98+
u32 record_size_limit;
99+
int rem, len = nlmsg_attrlen(info->nlhdr, GENL_HDRLEN);
100+
101+
nla_for_each_attr(nla, head, len, rem) {
102+
if (nla_type(nla) == HANDSHAKE_A_DONE_RECORD_SIZE_LIMIT) {
103+
record_size_limit = nla_get_u32(nla);
104+
if (treq->th_sock) {
105+
tls_ctx = tls_get_ctx(treq->th_sock->sk);
106+
tls_ctx->tls_record_size_limit = record_size_limit;
107+
}
108+
break;
109+
}
110+
}
111+
}
112+
88113
/**
89114
* tls_handshake_done - callback to handle a CMD_DONE request
90115
* @req: socket on which the handshake was performed
@@ -98,8 +123,10 @@ static void tls_handshake_done(struct handshake_req *req,
98123
struct tls_handshake_req *treq = handshake_req_private(req);
99124

100125
treq->th_peerid[0] = TLS_NO_PEERID;
101-
if (info)
126+
if (info) {
102127
tls_handshake_remote_peerids(treq, info);
128+
tls_handshake_record_size(treq, info);
129+
}
103130

104131
if (!status)
105132
set_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags);

net/tls/tls_sw.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,7 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg,
10371037
ssize_t copied = 0;
10381038
struct sk_msg *msg_pl, *msg_en;
10391039
struct tls_rec *rec;
1040+
u32 tls_record_size_limit;
10401041
int required_size;
10411042
int num_async = 0;
10421043
bool full_record;
@@ -1058,6 +1059,9 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg,
10581059
}
10591060
}
10601061

1062+
tls_record_size_limit = min_not_zero(tls_ctx->tls_record_size_limit,
1063+
TLS_MAX_PAYLOAD_SIZE);
1064+
10611065
while (msg_data_left(msg)) {
10621066
if (sk->sk_err) {
10631067
ret = -sk->sk_err;
@@ -1079,7 +1083,7 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg,
10791083
orig_size = msg_pl->sg.size;
10801084
full_record = false;
10811085
try_to_copy = msg_data_left(msg);
1082-
record_room = TLS_MAX_PAYLOAD_SIZE - msg_pl->sg.size;
1086+
record_room = tls_record_size_limit - msg_pl->sg.size;
10831087
if (try_to_copy >= record_room) {
10841088
try_to_copy = record_room;
10851089
full_record = true;

0 commit comments

Comments
 (0)