Skip to content

Commit f19008e

Browse files
almostivandavem330
authored andcommitted
tcp: correct read of TFO keys on big endian systems
When TFO keys are read back on big endian systems either via the global sysctl interface or via getsockopt() using TCP_FASTOPEN_KEY, the values don't match what was written. For example, on s390x: # echo "1-2-3-4" > /proc/sys/net/ipv4/tcp_fastopen_key # cat /proc/sys/net/ipv4/tcp_fastopen_key 02000000-01000000-04000000-03000000 Instead of: # cat /proc/sys/net/ipv4/tcp_fastopen_key 00000001-00000002-00000003-00000004 Fix this by converting to the correct endianness on read. This was reported by Colin Ian King when running the 'tcp_fastopen_backup_key' net selftest on s390x, which depends on the read value matching what was written. I've confirmed that the test now passes on big and little endian systems. Signed-off-by: Jason Baron <[email protected]> Fixes: 438ac88 ("net: fastopen: robustness and endianness fixes for SipHash") Cc: Ard Biesheuvel <[email protected]> Cc: Eric Dumazet <[email protected]> Reported-and-tested-by: Colin Ian King <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 56e287b commit f19008e

File tree

4 files changed

+33
-24
lines changed

4 files changed

+33
-24
lines changed

include/net/tcp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,6 +1672,8 @@ void tcp_fastopen_destroy_cipher(struct sock *sk);
16721672
void tcp_fastopen_ctx_destroy(struct net *net);
16731673
int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk,
16741674
void *primary_key, void *backup_key);
1675+
int tcp_fastopen_get_cipher(struct net *net, struct inet_connection_sock *icsk,
1676+
u64 *key);
16751677
void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb);
16761678
struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
16771679
struct request_sock *req,

net/ipv4/sysctl_net_ipv4.c

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -301,24 +301,16 @@ static int proc_tcp_fastopen_key(struct ctl_table *table, int write,
301301
struct ctl_table tbl = { .maxlen = ((TCP_FASTOPEN_KEY_LENGTH *
302302
2 * TCP_FASTOPEN_KEY_MAX) +
303303
(TCP_FASTOPEN_KEY_MAX * 5)) };
304-
struct tcp_fastopen_context *ctx;
305-
u32 user_key[TCP_FASTOPEN_KEY_MAX * 4];
306-
__le32 key[TCP_FASTOPEN_KEY_MAX * 4];
304+
u32 user_key[TCP_FASTOPEN_KEY_BUF_LENGTH / sizeof(u32)];
305+
__le32 key[TCP_FASTOPEN_KEY_BUF_LENGTH / sizeof(__le32)];
307306
char *backup_data;
308-
int ret, i = 0, off = 0, n_keys = 0;
307+
int ret, i = 0, off = 0, n_keys;
309308

310309
tbl.data = kmalloc(tbl.maxlen, GFP_KERNEL);
311310
if (!tbl.data)
312311
return -ENOMEM;
313312

314-
rcu_read_lock();
315-
ctx = rcu_dereference(net->ipv4.tcp_fastopen_ctx);
316-
if (ctx) {
317-
n_keys = tcp_fastopen_context_len(ctx);
318-
memcpy(&key[0], &ctx->key[0], TCP_FASTOPEN_KEY_LENGTH * n_keys);
319-
}
320-
rcu_read_unlock();
321-
313+
n_keys = tcp_fastopen_get_cipher(net, NULL, (u64 *)key);
322314
if (!n_keys) {
323315
memset(&key[0], 0, TCP_FASTOPEN_KEY_LENGTH);
324316
n_keys = 1;

net/ipv4/tcp.c

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3685,22 +3685,14 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
36853685
return 0;
36863686

36873687
case TCP_FASTOPEN_KEY: {
3688-
__u8 key[TCP_FASTOPEN_KEY_BUF_LENGTH];
3689-
struct tcp_fastopen_context *ctx;
3690-
unsigned int key_len = 0;
3688+
u64 key[TCP_FASTOPEN_KEY_BUF_LENGTH / sizeof(u64)];
3689+
unsigned int key_len;
36913690

36923691
if (get_user(len, optlen))
36933692
return -EFAULT;
36943693

3695-
rcu_read_lock();
3696-
ctx = rcu_dereference(icsk->icsk_accept_queue.fastopenq.ctx);
3697-
if (ctx) {
3698-
key_len = tcp_fastopen_context_len(ctx) *
3699-
TCP_FASTOPEN_KEY_LENGTH;
3700-
memcpy(&key[0], &ctx->key[0], key_len);
3701-
}
3702-
rcu_read_unlock();
3703-
3694+
key_len = tcp_fastopen_get_cipher(net, icsk, key) *
3695+
TCP_FASTOPEN_KEY_LENGTH;
37043696
len = min_t(unsigned int, len, key_len);
37053697
if (put_user(len, optlen))
37063698
return -EFAULT;

net/ipv4/tcp_fastopen.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,29 @@ int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk,
108108
return err;
109109
}
110110

111+
int tcp_fastopen_get_cipher(struct net *net, struct inet_connection_sock *icsk,
112+
u64 *key)
113+
{
114+
struct tcp_fastopen_context *ctx;
115+
int n_keys = 0, i;
116+
117+
rcu_read_lock();
118+
if (icsk)
119+
ctx = rcu_dereference(icsk->icsk_accept_queue.fastopenq.ctx);
120+
else
121+
ctx = rcu_dereference(net->ipv4.tcp_fastopen_ctx);
122+
if (ctx) {
123+
n_keys = tcp_fastopen_context_len(ctx);
124+
for (i = 0; i < n_keys; i++) {
125+
put_unaligned_le64(ctx->key[i].key[0], key + (i * 2));
126+
put_unaligned_le64(ctx->key[i].key[1], key + (i * 2) + 1);
127+
}
128+
}
129+
rcu_read_unlock();
130+
131+
return n_keys;
132+
}
133+
111134
static bool __tcp_fastopen_cookie_gen_cipher(struct request_sock *req,
112135
struct sk_buff *syn,
113136
const siphash_key_t *key,

0 commit comments

Comments
 (0)