mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-25 00:00:52 +07:00
Merge branch 'net-tls-add-socket-diag'
Davide Caratti says: ==================== net: tls: add socket diag The current kernel does not provide any diagnostic tool, except getsockopt(TCP_ULP), to know more about TCP sockets that have an upper layer protocol (ULP) on top of them. This series extends the set of information exported by INET_DIAG_INFO, to include data that are specific to the ULP (and that might be meaningful for debug/testing purposes). patch 1/3 ensures that the control plane reads/updates ULP specific data using RCU. patch 2/3 extends INET_DIAG_INFO and allows knowing the ULP name for each TCP socket that has done setsockopt(TCP_ULP) successfully. patch 3/3 extends kTLS to let programs like 'ss' know the protocol version and the cipher in use. Changes since v2: - remove unneeded #ifdef and fix reverse christmas tree in tls_get_info(), thanks to Jakub Kicinski Changes since v1: - don't worry about grace period when accessing ulp_ops, thanks to Jakub Kicinski and Eric Dumazet - use rcu_dereference() to access ULP data in tls get_info(), and test against NULL value, thanks to Jakub Kicinski - move RCU protected section inside tls get_info(), thanks to Jakub Kicinski Changes since RFC: - some coding style fixes, thanks to Jakub Kicinski - add X_UNSPEC as lowest value of uAPI enums, thanks to Jakub Kicinski - fix assignment of struct nlattr *start, thanks to Jakub Kicinski - let tls dump RXCONF and TXCONF, suggested by Jakub Kicinski - don't dump anything if TLS version or cipher are 0 (but still return a constant size in get_aux_size()), thanks to Boris Pismenny - constify first argument of get_info() and get_size() - use RCU to access access ulp_ops, like it's done for ca_ops - add patch 1/3, from Jakub Kicinski ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
1b6ca07b68
@ -97,7 +97,7 @@ struct inet_connection_sock {
|
||||
const struct tcp_congestion_ops *icsk_ca_ops;
|
||||
const struct inet_connection_sock_af_ops *icsk_af_ops;
|
||||
const struct tcp_ulp_ops *icsk_ulp_ops;
|
||||
void *icsk_ulp_data;
|
||||
void __rcu *icsk_ulp_data;
|
||||
void (*icsk_clean_acked)(struct sock *sk, u32 acked_seq);
|
||||
struct hlist_node icsk_listen_portaddr_node;
|
||||
unsigned int (*icsk_sync_mss)(struct sock *sk, u32 pmtu);
|
||||
|
@ -2122,6 +2122,9 @@ struct tcp_ulp_ops {
|
||||
void (*update)(struct sock *sk, struct proto *p);
|
||||
/* cleanup ulp */
|
||||
void (*release)(struct sock *sk);
|
||||
/* diagnostic */
|
||||
int (*get_info)(const struct sock *sk, struct sk_buff *skb);
|
||||
size_t (*get_info_size)(const struct sock *sk);
|
||||
|
||||
char name[TCP_ULP_NAME_MAX];
|
||||
struct module *owner;
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/skmsg.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
#include <net/tcp.h>
|
||||
#include <net/strparser.h>
|
||||
@ -290,6 +291,7 @@ struct tls_context {
|
||||
|
||||
struct list_head list;
|
||||
refcount_t refcount;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
enum tls_offload_ctx_dir {
|
||||
@ -348,7 +350,7 @@ struct tls_offload_context_rx {
|
||||
#define TLS_OFFLOAD_CONTEXT_SIZE_RX \
|
||||
(sizeof(struct tls_offload_context_rx) + TLS_DRIVER_STATE_SIZE_RX)
|
||||
|
||||
void tls_ctx_free(struct tls_context *ctx);
|
||||
void tls_ctx_free(struct sock *sk, struct tls_context *ctx);
|
||||
int wait_on_pending_writer(struct sock *sk, long *timeo);
|
||||
int tls_sk_query(struct sock *sk, int optname, char __user *optval,
|
||||
int __user *optlen);
|
||||
@ -429,6 +431,23 @@ static inline bool is_tx_ready(struct tls_sw_context_tx *ctx)
|
||||
return READ_ONCE(rec->tx_ready);
|
||||
}
|
||||
|
||||
static inline u16 tls_user_config(struct tls_context *ctx, bool tx)
|
||||
{
|
||||
u16 config = tx ? ctx->tx_conf : ctx->rx_conf;
|
||||
|
||||
switch (config) {
|
||||
case TLS_BASE:
|
||||
return TLS_CONF_BASE;
|
||||
case TLS_SW:
|
||||
return TLS_CONF_SW;
|
||||
case TLS_HW:
|
||||
return TLS_CONF_HW;
|
||||
case TLS_HW_RECORD:
|
||||
return TLS_CONF_HW_RECORD;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sk_buff *
|
||||
tls_validate_xmit_skb(struct sock *sk, struct net_device *dev,
|
||||
struct sk_buff *skb);
|
||||
@ -467,7 +486,10 @@ static inline struct tls_context *tls_get_ctx(const struct sock *sk)
|
||||
{
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
|
||||
return icsk->icsk_ulp_data;
|
||||
/* Use RCU on icsk_ulp_data only for sock diag code,
|
||||
* TLS data path doesn't need rcu_dereference().
|
||||
*/
|
||||
return (__force void *)icsk->icsk_ulp_data;
|
||||
}
|
||||
|
||||
static inline void tls_advance_record_sn(struct sock *sk,
|
||||
|
@ -153,11 +153,20 @@ enum {
|
||||
INET_DIAG_BBRINFO, /* request as INET_DIAG_VEGASINFO */
|
||||
INET_DIAG_CLASS_ID, /* request as INET_DIAG_TCLASS */
|
||||
INET_DIAG_MD5SIG,
|
||||
INET_DIAG_ULP_INFO,
|
||||
__INET_DIAG_MAX,
|
||||
};
|
||||
|
||||
#define INET_DIAG_MAX (__INET_DIAG_MAX - 1)
|
||||
|
||||
enum {
|
||||
INET_ULP_INFO_UNSPEC,
|
||||
INET_ULP_INFO_NAME,
|
||||
INET_ULP_INFO_TLS,
|
||||
__INET_ULP_INFO_MAX,
|
||||
};
|
||||
#define INET_ULP_INFO_MAX (__INET_ULP_INFO_MAX - 1)
|
||||
|
||||
/* INET_DIAG_MEM */
|
||||
|
||||
struct inet_diag_meminfo {
|
||||
|
@ -109,4 +109,19 @@ struct tls12_crypto_info_aes_ccm_128 {
|
||||
unsigned char rec_seq[TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE];
|
||||
};
|
||||
|
||||
enum {
|
||||
TLS_INFO_UNSPEC,
|
||||
TLS_INFO_VERSION,
|
||||
TLS_INFO_CIPHER,
|
||||
TLS_INFO_TXCONF,
|
||||
TLS_INFO_RXCONF,
|
||||
__TLS_INFO_MAX,
|
||||
};
|
||||
#define TLS_INFO_MAX (__TLS_INFO_MAX - 1)
|
||||
|
||||
#define TLS_CONF_BASE 1
|
||||
#define TLS_CONF_SW 2
|
||||
#define TLS_CONF_HW 3
|
||||
#define TLS_CONF_HW_RECORD 4
|
||||
|
||||
#endif /* _UAPI_LINUX_TLS_H */
|
||||
|
@ -345,7 +345,7 @@ 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))
|
||||
if (unlikely(rcu_access_pointer(icsk->icsk_ulp_data)))
|
||||
return -EINVAL;
|
||||
|
||||
link = sk_psock_init_link();
|
||||
|
@ -81,13 +81,42 @@ static int tcp_diag_put_md5sig(struct sk_buff *skb,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tcp_diag_put_ulp(struct sk_buff *skb, struct sock *sk,
|
||||
const struct tcp_ulp_ops *ulp_ops)
|
||||
{
|
||||
struct nlattr *nest;
|
||||
int err;
|
||||
|
||||
nest = nla_nest_start_noflag(skb, INET_DIAG_ULP_INFO);
|
||||
if (!nest)
|
||||
return -EMSGSIZE;
|
||||
|
||||
err = nla_put_string(skb, INET_ULP_INFO_NAME, ulp_ops->name);
|
||||
if (err)
|
||||
goto nla_failure;
|
||||
|
||||
if (ulp_ops->get_info)
|
||||
err = ulp_ops->get_info(sk, skb);
|
||||
if (err)
|
||||
goto nla_failure;
|
||||
|
||||
nla_nest_end(skb, nest);
|
||||
return 0;
|
||||
|
||||
nla_failure:
|
||||
nla_nest_cancel(skb, nest);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tcp_diag_get_aux(struct sock *sk, bool net_admin,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
int err = 0;
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
if (net_admin) {
|
||||
struct tcp_md5sig_info *md5sig;
|
||||
int err = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
md5sig = rcu_dereference(tcp_sk(sk)->md5sig_info);
|
||||
@ -99,11 +128,21 @@ static int tcp_diag_get_aux(struct sock *sk, bool net_admin,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (net_admin) {
|
||||
const struct tcp_ulp_ops *ulp_ops;
|
||||
|
||||
ulp_ops = icsk->icsk_ulp_ops;
|
||||
if (ulp_ops)
|
||||
err = tcp_diag_put_ulp(skb, sk, ulp_ops);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t tcp_diag_get_aux_size(struct sock *sk, bool net_admin)
|
||||
{
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
size_t size = 0;
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
@ -124,6 +163,17 @@ static size_t tcp_diag_get_aux_size(struct sock *sk, bool net_admin)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (net_admin) {
|
||||
const struct tcp_ulp_ops *ulp_ops;
|
||||
|
||||
ulp_ops = icsk->icsk_ulp_ops;
|
||||
if (ulp_ops) {
|
||||
size += nla_total_size(0) +
|
||||
nla_total_size(TCP_ULP_NAME_MAX);
|
||||
if (ulp_ops->get_info_size)
|
||||
size += ulp_ops->get_info_size(sk);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ static void tls_device_free_ctx(struct tls_context *ctx)
|
||||
if (ctx->rx_conf == TLS_HW)
|
||||
kfree(tls_offload_ctx_rx(ctx));
|
||||
|
||||
tls_ctx_free(ctx);
|
||||
tls_ctx_free(NULL, ctx);
|
||||
}
|
||||
|
||||
static void tls_device_gc_task(struct work_struct *work)
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/inet_diag.h>
|
||||
|
||||
#include <net/tls.h>
|
||||
|
||||
@ -251,14 +252,26 @@ static void tls_write_space(struct sock *sk)
|
||||
ctx->sk_write_space(sk);
|
||||
}
|
||||
|
||||
void tls_ctx_free(struct tls_context *ctx)
|
||||
/**
|
||||
* tls_ctx_free() - free TLS ULP context
|
||||
* @sk: socket to with @ctx is attached
|
||||
* @ctx: TLS context structure
|
||||
*
|
||||
* Free TLS context. If @sk is %NULL caller guarantees that the socket
|
||||
* to which @ctx was attached has no outstanding references.
|
||||
*/
|
||||
void tls_ctx_free(struct sock *sk, struct tls_context *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
memzero_explicit(&ctx->crypto_send, sizeof(ctx->crypto_send));
|
||||
memzero_explicit(&ctx->crypto_recv, sizeof(ctx->crypto_recv));
|
||||
kfree(ctx);
|
||||
|
||||
if (sk)
|
||||
kfree_rcu(ctx, rcu);
|
||||
else
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
static void tls_sk_proto_cleanup(struct sock *sk,
|
||||
@ -306,7 +319,7 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
|
||||
|
||||
write_lock_bh(&sk->sk_callback_lock);
|
||||
if (free_ctx)
|
||||
icsk->icsk_ulp_data = NULL;
|
||||
rcu_assign_pointer(icsk->icsk_ulp_data, NULL);
|
||||
sk->sk_prot = ctx->sk_proto;
|
||||
if (sk->sk_write_space == tls_write_space)
|
||||
sk->sk_write_space = ctx->sk_write_space;
|
||||
@ -321,7 +334,7 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
|
||||
ctx->sk_proto_close(sk, timeout);
|
||||
|
||||
if (free_ctx)
|
||||
tls_ctx_free(ctx);
|
||||
tls_ctx_free(sk, ctx);
|
||||
}
|
||||
|
||||
static int do_tls_getsockopt_tx(struct sock *sk, char __user *optval,
|
||||
@ -610,7 +623,7 @@ static struct tls_context *create_ctx(struct sock *sk)
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
icsk->icsk_ulp_data = ctx;
|
||||
rcu_assign_pointer(icsk->icsk_ulp_data, ctx);
|
||||
ctx->setsockopt = sk->sk_prot->setsockopt;
|
||||
ctx->getsockopt = sk->sk_prot->getsockopt;
|
||||
ctx->sk_proto_close = sk->sk_prot->close;
|
||||
@ -651,8 +664,8 @@ static void tls_hw_sk_destruct(struct sock *sk)
|
||||
|
||||
ctx->sk_destruct(sk);
|
||||
/* Free ctx */
|
||||
tls_ctx_free(ctx);
|
||||
icsk->icsk_ulp_data = NULL;
|
||||
rcu_assign_pointer(icsk->icsk_ulp_data, NULL);
|
||||
tls_ctx_free(sk, ctx);
|
||||
}
|
||||
|
||||
static int tls_hw_prot(struct sock *sk)
|
||||
@ -823,6 +836,67 @@ static void tls_update(struct sock *sk, struct proto *p)
|
||||
}
|
||||
}
|
||||
|
||||
static int tls_get_info(const struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
u16 version, cipher_type;
|
||||
struct tls_context *ctx;
|
||||
struct nlattr *start;
|
||||
int err;
|
||||
|
||||
start = nla_nest_start_noflag(skb, INET_ULP_INFO_TLS);
|
||||
if (!start)
|
||||
return -EMSGSIZE;
|
||||
|
||||
rcu_read_lock();
|
||||
ctx = rcu_dereference(inet_csk(sk)->icsk_ulp_data);
|
||||
if (!ctx) {
|
||||
err = 0;
|
||||
goto nla_failure;
|
||||
}
|
||||
version = ctx->prot_info.version;
|
||||
if (version) {
|
||||
err = nla_put_u16(skb, TLS_INFO_VERSION, version);
|
||||
if (err)
|
||||
goto nla_failure;
|
||||
}
|
||||
cipher_type = ctx->prot_info.cipher_type;
|
||||
if (cipher_type) {
|
||||
err = nla_put_u16(skb, TLS_INFO_CIPHER, cipher_type);
|
||||
if (err)
|
||||
goto nla_failure;
|
||||
}
|
||||
err = nla_put_u16(skb, TLS_INFO_TXCONF, tls_user_config(ctx, true));
|
||||
if (err)
|
||||
goto nla_failure;
|
||||
|
||||
err = nla_put_u16(skb, TLS_INFO_RXCONF, tls_user_config(ctx, false));
|
||||
if (err)
|
||||
goto nla_failure;
|
||||
|
||||
rcu_read_unlock();
|
||||
nla_nest_end(skb, start);
|
||||
return 0;
|
||||
|
||||
nla_failure:
|
||||
rcu_read_unlock();
|
||||
nla_nest_cancel(skb, start);
|
||||
return err;
|
||||
}
|
||||
|
||||
static size_t tls_get_info_size(const struct sock *sk)
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
size += nla_total_size(0) + /* INET_ULP_INFO_TLS */
|
||||
nla_total_size(sizeof(u16)) + /* TLS_INFO_VERSION */
|
||||
nla_total_size(sizeof(u16)) + /* TLS_INFO_CIPHER */
|
||||
nla_total_size(sizeof(u16)) + /* TLS_INFO_RXCONF */
|
||||
nla_total_size(sizeof(u16)) + /* TLS_INFO_TXCONF */
|
||||
0;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void tls_register_device(struct tls_device *device)
|
||||
{
|
||||
spin_lock_bh(&device_spinlock);
|
||||
@ -844,6 +918,8 @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = {
|
||||
.owner = THIS_MODULE,
|
||||
.init = tls_init,
|
||||
.update = tls_update,
|
||||
.get_info = tls_get_info,
|
||||
.get_info_size = tls_get_info_size,
|
||||
};
|
||||
|
||||
static int __init tls_register(void)
|
||||
|
Loading…
Reference in New Issue
Block a user