Skip to content

Commit

Permalink
Merge branch 'bpf-sockmap-tls-fixes'
Browse files Browse the repository at this point in the history
Jakub Kicinski says:

====================
John says:

Resolve a series of splats discovered by syzbot and an unhash
TLS issue noted by Eric Dumazet.

The main issues revolved around interaction between TLS and
sockmap tear down. TLS and sockmap could both reset sk->prot
ops creating a condition where a close or unhash op could be
called forever. A rare race condition resulting from a missing
rcu sync operation was causing a use after free. Then on the
TLS side dropping the sock lock and re-acquiring it during the
close op could hang. Finally, sockmap must be deployed before
tls for current stack assumptions to be met. This is enforced
now. A feature series can enable it.

To fix this first refactor TLS code so the lock is held for the
entire teardown operation. Then add an unhash callback to ensure
TLS can not transition from ESTABLISHED to LISTEN state. This
transition is a similar bug to the one found and fixed previously
in sockmap. Then apply three fixes to sockmap to fix up races
on tear down around map free and close. Finally, if sockmap
is destroyed before TLS we add a new ULP op update to inform
the TLS stack it should not call sockmap ops. This last one
appears to be the most commonly found issue from syzbot.

v4:
 - fix some use after frees;
 - disable disconnect work for offload (ctx lifetime is much
   more complex);
 - remove some of the dead code which made it hard to understand
   (for me) that things work correctly (e.g. the checks TLS is
   the top ULP);
 - add selftets.
====================

Signed-off-by: Daniel Borkmann <[email protected]>
  • Loading branch information
borkmann committed Jul 22, 2019
2 parents 1d4126c + d4d3418 commit 57ebc62
Show file tree
Hide file tree
Showing 10 changed files with 419 additions and 68 deletions.
6 changes: 6 additions & 0 deletions Documentation/networking/tls-offload.rst
Original file line number Diff line number Diff line change
Expand Up @@ -513,3 +513,9 @@ Redirects leak clear text

In the RX direction, if segment has already been decrypted by the device
and it gets redirected or mirrored - clear text will be transmitted out.

shutdown() doesn't clear TLS state
----------------------------------

shutdown() system call allows for a TLS socket to be reused as a different
connection. Offload doesn't currently handle that.
8 changes: 7 additions & 1 deletion include/linux/skmsg.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,13 @@ static inline void sk_psock_restore_proto(struct sock *sk,
sk->sk_write_space = psock->saved_write_space;

if (psock->sk_proto) {
sk->sk_prot = psock->sk_proto;
struct inet_connection_sock *icsk = inet_csk(sk);
bool has_ulp = !!icsk->icsk_ulp_data;

if (has_ulp)
tcp_update_ulp(sk, psock->sk_proto);
else
sk->sk_prot = psock->sk_proto;
psock->sk_proto = NULL;
}
}
Expand Down
3 changes: 3 additions & 0 deletions include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -2103,6 +2103,8 @@ struct tcp_ulp_ops {

/* initialize ulp */
int (*init)(struct sock *sk);
/* update ulp */
void (*update)(struct sock *sk, struct proto *p);
/* cleanup ulp */
void (*release)(struct sock *sk);

Expand All @@ -2114,6 +2116,7 @@ void tcp_unregister_ulp(struct tcp_ulp_ops *type);
int tcp_set_ulp(struct sock *sk, const char *name);
void tcp_get_available_ulp(char *buf, size_t len);
void tcp_cleanup_ulp(struct sock *sk);
void tcp_update_ulp(struct sock *sk, struct proto *p);

#define MODULE_ALIAS_TCP_ULP(name) \
__MODULE_INFO(alias, alias_userspace, name); \
Expand Down
15 changes: 11 additions & 4 deletions include/net/tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,7 @@ struct tls_device {
enum {
TLS_BASE,
TLS_SW,
#ifdef CONFIG_TLS_DEVICE
TLS_HW,
#endif
TLS_HW_RECORD,
TLS_NUM_CONFIG,
};
Expand Down Expand Up @@ -162,6 +160,7 @@ struct tls_sw_context_tx {
int async_capable;

#define BIT_TX_SCHEDULED 0
#define BIT_TX_CLOSING 1
unsigned long tx_bitmask;
};

Expand Down Expand Up @@ -272,6 +271,8 @@ struct tls_context {
unsigned long flags;

/* cache cold stuff */
struct proto *sk_proto;

void (*sk_destruct)(struct sock *sk);
void (*sk_proto_close)(struct sock *sk, long timeout);

Expand All @@ -289,6 +290,8 @@ struct tls_context {

struct list_head list;
refcount_t refcount;

struct work_struct gc;
};

enum tls_offload_ctx_dir {
Expand Down Expand Up @@ -355,13 +358,17 @@ int tls_sk_attach(struct sock *sk, int optname, char __user *optval,
unsigned int optlen);

int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx);
void tls_sw_strparser_arm(struct sock *sk, struct tls_context *ctx);
void tls_sw_strparser_done(struct tls_context *tls_ctx);
int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
int tls_sw_sendpage(struct sock *sk, struct page *page,
int offset, size_t size, int flags);
void tls_sw_close(struct sock *sk, long timeout);
void tls_sw_free_resources_tx(struct sock *sk);
void tls_sw_cancel_work_tx(struct tls_context *tls_ctx);
void tls_sw_release_resources_tx(struct sock *sk);
void tls_sw_free_ctx_tx(struct tls_context *tls_ctx);
void tls_sw_free_resources_rx(struct sock *sk);
void tls_sw_release_resources_rx(struct sock *sk);
void tls_sw_free_ctx_rx(struct tls_context *tls_ctx);
int tls_sw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
int nonblock, int flags, int *addr_len);
bool tls_sw_stream_read(const struct sock *sk);
Expand Down
4 changes: 2 additions & 2 deletions net/core/skmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,12 +585,12 @@ EXPORT_SYMBOL_GPL(sk_psock_destroy);

void sk_psock_drop(struct sock *sk, struct sk_psock *psock)
{
rcu_assign_sk_user_data(sk, NULL);
sk_psock_cork_free(psock);
sk_psock_zap_ingress(psock);
sk_psock_restore_proto(sk, psock);

write_lock_bh(&sk->sk_callback_lock);
sk_psock_restore_proto(sk, psock);
rcu_assign_sk_user_data(sk, NULL);
if (psock->progs.skb_parser)
sk_psock_stop_strp(sk, psock);
write_unlock_bh(&sk->sk_callback_lock);
Expand Down
19 changes: 14 additions & 5 deletions net/core/sock_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ static void sock_map_free(struct bpf_map *map)
raw_spin_unlock_bh(&stab->lock);
rcu_read_unlock();

synchronize_rcu();

bpf_map_area_free(stab->sks);
kfree(stab);
}
Expand Down Expand Up @@ -276,16 +278,20 @@ static int __sock_map_delete(struct bpf_stab *stab, struct sock *sk_test,
struct sock **psk)
{
struct sock *sk;
int err = 0;

raw_spin_lock_bh(&stab->lock);
sk = *psk;
if (!sk_test || sk_test == sk)
*psk = NULL;
sk = xchg(psk, NULL);

if (likely(sk))
sock_map_unref(sk, psk);
else
err = -EINVAL;

raw_spin_unlock_bh(&stab->lock);
if (unlikely(!sk))
return -EINVAL;
sock_map_unref(sk, psk);
return 0;
return err;
}

static void sock_map_delete_from_link(struct bpf_map *map, struct sock *sk,
Expand Down Expand Up @@ -328,6 +334,7 @@ static int sock_map_update_common(struct bpf_map *map, u32 idx,
struct sock *sk, u64 flags)
{
struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
struct inet_connection_sock *icsk = inet_csk(sk);
struct sk_psock_link *link;
struct sk_psock *psock;
struct sock *osk;
Expand All @@ -338,6 +345,8 @@ static int sock_map_update_common(struct bpf_map *map, u32 idx,
return -EINVAL;
if (unlikely(idx >= map->max_entries))
return -E2BIG;
if (unlikely(icsk->icsk_ulp_data))
return -EINVAL;

link = sk_psock_init_link();
if (!link)
Expand Down
13 changes: 13 additions & 0 deletions net/ipv4/tcp_ulp.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,19 @@ void tcp_get_available_ulp(char *buf, size_t maxlen)
rcu_read_unlock();
}

void tcp_update_ulp(struct sock *sk, struct proto *proto)
{
struct inet_connection_sock *icsk = inet_csk(sk);

if (!icsk->icsk_ulp_ops) {
sk->sk_prot = proto;
return;
}

if (icsk->icsk_ulp_ops->update)
icsk->icsk_ulp_ops->update(sk, proto);
}

void tcp_cleanup_ulp(struct sock *sk)
{
struct inet_connection_sock *icsk = inet_csk(sk);
Expand Down
Loading

0 comments on commit 57ebc62

Please sign in to comment.