Skip to content

Commit

Permalink
tcp: correct read of TFO keys on big endian systems
Browse files Browse the repository at this point in the history
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 <jbaron@akamai.com>
Fixes: 438ac88 ("net: fastopen: robustness and endianness fixes for SipHash")
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Eric Dumazet <edumazet@google.com>
Reported-and-tested-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jason Baron authored and David S. Miller committed Aug 10, 2020
1 parent 56e287b commit f19008e
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 24 deletions.
2 changes: 2 additions & 0 deletions include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1672,6 +1672,8 @@ void tcp_fastopen_destroy_cipher(struct sock *sk);
void tcp_fastopen_ctx_destroy(struct net *net);
int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk,
void *primary_key, void *backup_key);
int tcp_fastopen_get_cipher(struct net *net, struct inet_connection_sock *icsk,
u64 *key);
void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb);
struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
Expand Down
16 changes: 4 additions & 12 deletions net/ipv4/sysctl_net_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,24 +301,16 @@ static int proc_tcp_fastopen_key(struct ctl_table *table, int write,
struct ctl_table tbl = { .maxlen = ((TCP_FASTOPEN_KEY_LENGTH *
2 * TCP_FASTOPEN_KEY_MAX) +
(TCP_FASTOPEN_KEY_MAX * 5)) };
struct tcp_fastopen_context *ctx;
u32 user_key[TCP_FASTOPEN_KEY_MAX * 4];
__le32 key[TCP_FASTOPEN_KEY_MAX * 4];
u32 user_key[TCP_FASTOPEN_KEY_BUF_LENGTH / sizeof(u32)];
__le32 key[TCP_FASTOPEN_KEY_BUF_LENGTH / sizeof(__le32)];
char *backup_data;
int ret, i = 0, off = 0, n_keys = 0;
int ret, i = 0, off = 0, n_keys;

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

rcu_read_lock();
ctx = rcu_dereference(net->ipv4.tcp_fastopen_ctx);
if (ctx) {
n_keys = tcp_fastopen_context_len(ctx);
memcpy(&key[0], &ctx->key[0], TCP_FASTOPEN_KEY_LENGTH * n_keys);
}
rcu_read_unlock();

n_keys = tcp_fastopen_get_cipher(net, NULL, (u64 *)key);
if (!n_keys) {
memset(&key[0], 0, TCP_FASTOPEN_KEY_LENGTH);
n_keys = 1;
Expand Down
16 changes: 4 additions & 12 deletions net/ipv4/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -3685,22 +3685,14 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
return 0;

case TCP_FASTOPEN_KEY: {
__u8 key[TCP_FASTOPEN_KEY_BUF_LENGTH];
struct tcp_fastopen_context *ctx;
unsigned int key_len = 0;
u64 key[TCP_FASTOPEN_KEY_BUF_LENGTH / sizeof(u64)];
unsigned int key_len;

if (get_user(len, optlen))
return -EFAULT;

rcu_read_lock();
ctx = rcu_dereference(icsk->icsk_accept_queue.fastopenq.ctx);
if (ctx) {
key_len = tcp_fastopen_context_len(ctx) *
TCP_FASTOPEN_KEY_LENGTH;
memcpy(&key[0], &ctx->key[0], key_len);
}
rcu_read_unlock();

key_len = tcp_fastopen_get_cipher(net, icsk, key) *
TCP_FASTOPEN_KEY_LENGTH;
len = min_t(unsigned int, len, key_len);
if (put_user(len, optlen))
return -EFAULT;
Expand Down
23 changes: 23 additions & 0 deletions net/ipv4/tcp_fastopen.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,29 @@ int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk,
return err;
}

int tcp_fastopen_get_cipher(struct net *net, struct inet_connection_sock *icsk,
u64 *key)
{
struct tcp_fastopen_context *ctx;
int n_keys = 0, i;

rcu_read_lock();
if (icsk)
ctx = rcu_dereference(icsk->icsk_accept_queue.fastopenq.ctx);
else
ctx = rcu_dereference(net->ipv4.tcp_fastopen_ctx);
if (ctx) {
n_keys = tcp_fastopen_context_len(ctx);
for (i = 0; i < n_keys; i++) {
put_unaligned_le64(ctx->key[i].key[0], key + (i * 2));
put_unaligned_le64(ctx->key[i].key[1], key + (i * 2) + 1);
}
}
rcu_read_unlock();

return n_keys;
}

static bool __tcp_fastopen_cookie_gen_cipher(struct request_sock *req,
struct sk_buff *syn,
const siphash_key_t *key,
Expand Down

0 comments on commit f19008e

Please sign in to comment.