:p
atchew
Login
From: Geliang Tang <tanggeliang@kylinos.cn> v16: - drop rcu_head from struct tls_proto, use refcnt for lifecycle management. - add back TLS_NUM_PROTS to handle IPv4/IPv6 separately. - add .owner field to tls_tcp_ops and tls_mptcp_ops (THIS_MODULE). - add module refcounting (try_module_get / module_put) in tls_build_proto and tls_init. - add missing NULL check for tls_ctx->proto->ops in tls_sk_poll. - add RCU read lock protection in tls_register_prot_ops. - add error handling for tls_register_prot_ops calls in tls_register (with rollback on failure). - adjust MPTCP cleanup: move tcp_cleanup_ulp from mptcp_destroy_common to mptcp_destroy. - remove increase_rlimit from selftest and fix fd check. v15: - patch 1: add proto parameter for tls_toe_bypass. - patch 1: add a proto null-check in update_sk_prot. - patch 1: hold mutex_lock in tls_proto_cleanup. - patch 14: raise the limit of file descriptor values to 4096 to avoid test failures. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1776469068.git.tanggeliang@kylinos.cn/ v14: - address review comments from sashiko - patch 1: add rcu for tls_proto, add tls_proto_cleanup. - patch 2: add unregister helper. - patch 3: add tls_prot_ops pointer to tls_proto, instead of tls_context - patch 5: update mptcp_get_skb_seq, using map_seq - offset, then the patch "tls: add skb offset check for mptcp" can be dropped. - patch 7: check len < 0. - patch 8: call tcp_cleanup_ulp in mptcp_destroy_common. - patch 9: replace all "tls" as "espintcp" in sock_test_tcpulp. - patch 10: add is_mptcp_enable helper. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1775476921.git.tanggeliang@kylinos.cn/ v13: - patch 1: Add new patch "add per-protocol cache" to address AI review. - patch 2: Hold RCU read lock in tls_prot_ops_find(). - patch 3: Set icsk_ulp_data to NULL in error path. - patch 6: Use spin_is_locked() instead of lockdep_is_held() to fix build errors. - patch 9: Drop tcp_sock_set_ulp(). - patch 11: Remove the "return" statement in ulp_sock_pair and check the return values of socket(). - patch 14: Update wait_for_tcp_close(). - patch 16: Add a max argument to init() and set it to '0' to disable multipath testing, so that this series does not depend on the "mptcp: fix stall because of data_ready" series. Multipath testing will be re‑enabled together with that series later, as a squash‑to patch. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1775227717.git.tanggeliang@kylinos.cn/ v12: - Thanks for the help from Paolo and Gang Yan, I finally solved the deadlock issue in read_sock. As a result, the patch "mptcp: avoid sleeping in read_sock path under softirq" in v11 has been dropped, and instead a lock_is_held interface has been added to struct tls_prot_ops. When MPTCP implements this interface, it not only checks sock_owned_by_user_nocheck(sk) as TCP does, but also needs to check whether the MPTCP data lock is held. - Update selftests to make them more stable. - Fix shellcheck errors for the selftests. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1775115102.git.tanggeliang@kylinos.cn/ v11: - Fix memory leak errors reported by CI. In v10, these occurred in the shutdown_reuse test and "usleep(500000)" caused the memory leaks. In v11, a dedicated helper wait_for_tcp_close() has been added to provide an appropriate delay. - Drop the code that used mptcp_data_trylock() in mptcp_move_skbs() to fix a deadlock issue, as that deadlock no longer occurs in v11. - Do not add "mptcp" variable for the "tls_err" tests, adding it for the "tls" tests is sufficient. - No longer increase timeout values for poll/epoll tests, as they are no longer needed. - Add ns1 definition in mptcp_tls.sh to fix "ns1 is referenced but not assigned" error. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1773911536.git.tanggeliang@kylinos.cn/ v10: - Address comments by ai review: - patch 2: call tls_ctx_free(sk, ctx) and clear icsk_ulp_data before goto out. - patch 3: update commit log as "validate each SKB's offset except the first". - patch 5: add sock_owned_by_user() checks. - patch 7: disable device offload for MPTCP sockets. - patch 9: use TCP_ULP_NAME_MAX in mptcp_setsockopt_tcp_ulp(), drop SOL_TLS in mptcp_supported_sockopt(). - Make .get_skb_off optional instead of mandatory, TCP does not need to define it. - Test "espintcp" ULP instead of "smc" in patch 10. "smc" ULP is removed recently. - With Gang Yan's "mptcp: fix stall because of data_ready" v3, mptcp tls selftests can run without failures. Now add them in this set. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1773737371.git.tanggeliang@kylinos.cn/ v9: - add a new patch to "add MPTCP SKB offset check in strp queue walk", thanks to Gang Yan for the fix. - add a new patch to "avoid deadlocks in read_sock path", replacing the "in_softirq()" check used in v8. - update the selftests. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1773365606.git.tanggeliang@kylinos.cn/ v8: - do not hold tls_prot_ops_lock in tls_init(); otherwise, a deadlock occurs. - change return value of mptcp_stream_is_readable() as 'bool' to fix the "expected restricted __poll_t" warning reported by CI. - fixed other CI checkpatch warnings regarding excessively long lines. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1768294706.git.tanggeliang@kylinos.cn/ v7: - Passing an MPTCP socket to tcp_sock_rate_check_app_limited() causes a crash. In v7, an MPTCP version of check_app_limited() is implemented, which calls tcp_sock_rate_check_app_limited() for each subflow. - Register tls_tcp_ops and tls_mptcp_ops in tls_register() rather than in tls_init(). - Set ctx->ops in tls_init() instead of in do_tls_setsockopt_conf(). - Keep tls_device.c unchanged. MPTCP TLS_HW mode has not been implemented yet, so EOPNOTSUPP is returned in this case. - Also add TCP TLS tests in mptcp_join.sh. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1768284047.git.tanggeliang@kylinos.cn/ v6: - register each ops as Matt suggested. - drop sk_is_msk(). - add tcp_sock_get_ulp/tcp_sock_set_ulp helpers. - set another ULP in sock_test_tcpulp as Matt suggested. - add tls tests using multiple subflows in mptcp_join.sh. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1767518836.git.tanggeliang@kylinos.cn/ v5: - As suggested by Mat and Matt, this set introduces struct tls_prot_ops for TLS. - Includes Gang Yan's patches to add MPTCP support to the TLS selftests. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1766372799.git.tanggeliang@kylinos.cn/ v4: - split "tls: add MPTCP protocol support" into smaller, more focused patches. - a new mptcp_inq helper has been implemented instead of directly using mptcp_inq_hint to fix the issue mentioned in [1]. - add sk_is_msk helper. - the 'expect' parameter will no longer be added to sock_test_tcpulp. Instead, SOCK_TEST_TCPULP items causing the tests failure will be directly removed. - remove the "TCP KTLS" tests, keeping only the MPTCP-related ones. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1765505775.git.tanggeliang@kylinos.cn/ [1] https://patchwork.kernel.org/project/mptcp/patch/ce74452f4c095a1761ef493b767b4bd9f9c14359.1764333805.git.tanggeliang@kylinos.cn/ v3: - mptcp_read_sock() and mptcp_poll() are not exported, as mptcp_sockopt test does not use read_sock/poll interfaces. They will be exported when new tests are added in the future. - call mptcp_inq_hint in tls_device_rx_resync_new_rec(), tls_device_core_ctrl_rx_resync() and tls_read_flush_backlog() too. - update selftests. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1763800601.git.tanggeliang@kylinos.cn/ v2: - fix disconnect. - update selftests. This series adds KTLS support for MPTCP. Since the ULP of msk is not being used, ULP KTLS can be directly configured onto msk without affecting its communication. Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/480 Gang Yan (1): mptcp: update mptcp_check_readable Geliang Tang (15): tls: add per-protocol cache to support mptcp tls: introduce struct tls_prot_ops tls: add tls_prot_ops pointer to tls_proto tls: replace direct protocol calls with tls_proto->ops mptcp: implement tls_mptcp_ops tls: disable device offload for mptcp sockets mptcp: update ulp getsockopt for tls support mptcp: enable ulp setsockopt for tls support selftests: mptcp: connect: use espintcp for ulp test selftests: tls: add mptcp variant for testing selftests: tls: increase pollin timeouts for mptcp selftests: tls: increase nonblocking data size for mptcp selftests: tls: wait close in shutdown_reuse for mptcp selftests: tls: add mptcp test cases selftests: mptcp: cover mptcp tls tests include/linux/tcp.h | 1 + include/net/mptcp.h | 2 + include/net/tcp.h | 1 + include/net/tls.h | 36 +++ include/net/tls_toe.h | 3 +- net/ipv4/tcp.c | 45 +-- net/mptcp/protocol.c | 118 +++++++- net/mptcp/protocol.h | 1 + net/mptcp/sockopt.c | 53 +++- net/tls/tls.h | 3 +- net/tls/tls_device.c | 6 + net/tls/tls_main.c | 270 +++++++++++++++--- net/tls/tls_strp.c | 33 ++- net/tls/tls_sw.c | 7 +- net/tls/tls_toe.c | 5 +- tools/testing/selftests/net/mptcp/.gitignore | 1 + tools/testing/selftests/net/mptcp/Makefile | 2 + tools/testing/selftests/net/mptcp/config | 5 + .../selftests/net/mptcp/mptcp_connect.c | 4 +- .../testing/selftests/net/mptcp/mptcp_tls.sh | 62 ++++ tools/testing/selftests/net/mptcp/tls.c | 1 + tools/testing/selftests/net/tls.c | 174 ++++++++++- 22 files changed, 736 insertions(+), 97 deletions(-) create mode 100755 tools/testing/selftests/net/mptcp/mptcp_tls.sh create mode 120000 tools/testing/selftests/net/mptcp/tls.c -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> The TLS ULP uses a single global array to cache base protocol operations. When MPTCP sockets enable TLS, they overwrite this global cache with mptcp_prot, causing active TCP TLS sockets to use MPTCP-specific ops. This leads to type confusion and kernel panics. Fix by replacing the global cache with a per-protocol linked list. Each protocol (TCP, MPTCP, etc.) now has its own cached operations, stored in struct tls_proto and referenced from tls_context. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- include/net/tls.h | 16 ++++++ include/net/tls_toe.h | 3 +- net/tls/tls.h | 3 +- net/tls/tls_main.c | 126 ++++++++++++++++++++++++++++-------------- net/tls/tls_toe.c | 5 +- 5 files changed, 106 insertions(+), 47 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -XXX,XX +XXX,XX @@ struct tls_prot_info { u16 tail_size; }; +enum { + TLSV4, + TLSV6, + TLS_NUM_PROTS, +}; + +struct tls_proto { + refcount_t refcnt; + struct list_head list; + const struct proto *prot; + struct proto prots[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG]; + struct proto_ops proto_ops[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG]; +}; + struct tls_context { /* read-only cache line */ struct tls_prot_info prot_info; @@ -XXX,XX +XXX,XX @@ struct tls_context { struct proto *sk_proto; struct sock *sk; + struct tls_proto *proto; + void (*sk_destruct)(struct sock *sk); union tls_crypto_context crypto_send; diff --git a/include/net/tls_toe.h b/include/net/tls_toe.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/tls_toe.h +++ b/include/net/tls_toe.h @@ -XXX,XX +XXX,XX @@ struct tls_toe_device { struct kref kref; }; -int tls_toe_bypass(struct sock *sk); +int tls_toe_bypass(struct sock *sk, + struct tls_proto *proto); int tls_toe_hash(struct sock *sk); void tls_toe_unhash(struct sock *sk); diff --git a/net/tls/tls.h b/net/tls/tls.h index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls.h +++ b/net/tls/tls.h @@ -XXX,XX +XXX,XX @@ struct tls_rec { int __net_init tls_proc_init(struct net *net); void __net_exit tls_proc_fini(struct net *net); -struct tls_context *tls_ctx_create(struct sock *sk); +struct tls_context *tls_ctx_create(struct sock *sk, + struct tls_proto *proto); void tls_ctx_free(struct sock *sk, struct tls_context *ctx); void update_sk_prot(struct sock *sk, struct tls_context *ctx); diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -XXX,XX +XXX,XX @@ MODULE_DESCRIPTION("Transport Layer Security Support"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS_TCP_ULP("tls"); -enum { - TLSV4, - TLSV6, - TLS_NUM_PROTS, -}; - #define CHECK_CIPHER_DESC(cipher,ci) \ static_assert(cipher ## _IV_SIZE <= TLS_MAX_IV_SIZE); \ static_assert(cipher ## _SALT_SIZE <= TLS_MAX_SALT_SIZE); \ @@ -XXX,XX +XXX,XX @@ CHECK_CIPHER_DESC(TLS_CIPHER_SM4_CCM, tls12_crypto_info_sm4_ccm); CHECK_CIPHER_DESC(TLS_CIPHER_ARIA_GCM_128, tls12_crypto_info_aria_gcm_128); CHECK_CIPHER_DESC(TLS_CIPHER_ARIA_GCM_256, tls12_crypto_info_aria_gcm_256); -static const struct proto *saved_tcpv6_prot; -static DEFINE_MUTEX(tcpv6_prot_mutex); -static const struct proto *saved_tcpv4_prot; -static DEFINE_MUTEX(tcpv4_prot_mutex); -static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG]; -static struct proto_ops tls_proto_ops[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG]; +static LIST_HEAD(tls_proto_list); +static DEFINE_MUTEX(tls_proto_mutex); static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], const struct proto *base); +static struct tls_proto *tls_proto_find(const struct proto *prot) +{ + struct tls_proto *proto, *ret = NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(proto, &tls_proto_list, list) { + if (proto->prot == prot) { + if (refcount_inc_not_zero(&proto->refcnt)) + ret = proto; + break; + } + } + rcu_read_unlock(); + return ret; +} + +static void tls_proto_cleanup(void) +{ + struct tls_proto *prot, *tmp; + + mutex_lock(&tls_proto_mutex); + list_for_each_entry_safe(prot, tmp, &tls_proto_list, list) { + if (refcount_dec_and_test(&prot->refcnt)) { + list_del_rcu(&prot->list); + synchronize_rcu(); + kfree(prot); + } + } + mutex_unlock(&tls_proto_mutex); +} + void update_sk_prot(struct sock *sk, struct tls_context *ctx) { int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4; + struct tls_proto *proto = ctx->proto; + + if (!proto) + return; WRITE_ONCE(sk->sk_prot, - &tls_prots[ip_ver][ctx->tx_conf][ctx->rx_conf]); + &proto->prots[ip_ver][ctx->tx_conf][ctx->rx_conf]); WRITE_ONCE(sk->sk_socket->ops, - &tls_proto_ops[ip_ver][ctx->tx_conf][ctx->rx_conf]); + &proto->proto_ops[ip_ver][ctx->tx_conf][ctx->rx_conf]); } int wait_on_pending_writer(struct sock *sk, long *timeo) @@ -XXX,XX +XXX,XX @@ void tls_ctx_free(struct sock *sk, struct tls_context *ctx) if (!ctx) return; + if (ctx->proto) { + if (refcount_dec_and_test(&ctx->proto->refcnt)) { + list_del_rcu(&ctx->proto->list); + synchronize_rcu(); + kfree(ctx->proto); + } + } + memzero_explicit(&ctx->crypto_send, sizeof(ctx->crypto_send)); memzero_explicit(&ctx->crypto_recv, sizeof(ctx->crypto_recv)); mutex_destroy(&ctx->tx_lock); @@ -XXX,XX +XXX,XX @@ static int tls_disconnect(struct sock *sk, int flags) return -EOPNOTSUPP; } -struct tls_context *tls_ctx_create(struct sock *sk) +struct tls_context *tls_ctx_create(struct sock *sk, + struct tls_proto *proto) { struct inet_connection_sock *icsk = inet_csk(sk); struct tls_context *ctx; @@ -XXX,XX +XXX,XX @@ struct tls_context *tls_ctx_create(struct sock *sk) mutex_init(&ctx->tx_lock); ctx->sk_proto = READ_ONCE(sk->sk_prot); + ctx->proto = proto; ctx->sk = sk; /* Release semantic of rcu_assign_pointer() ensures that * ctx->sk_proto is visible before changing sk->sk_prot in @@ -XXX,XX +XXX,XX @@ static void build_proto_ops(struct proto_ops ops[TLS_NUM_CONFIG][TLS_NUM_CONFIG] #endif } -static void tls_build_proto(struct sock *sk) +static struct tls_proto *tls_build_proto(struct sock *sk) { int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4; struct proto *prot = READ_ONCE(sk->sk_prot); + struct tls_proto *proto; - /* Build IPv6 TLS whenever the address of tcpv6 _prot changes */ - if (ip_ver == TLSV6 && - unlikely(prot != smp_load_acquire(&saved_tcpv6_prot))) { - mutex_lock(&tcpv6_prot_mutex); - if (likely(prot != saved_tcpv6_prot)) { - build_protos(tls_prots[TLSV6], prot); - build_proto_ops(tls_proto_ops[TLSV6], - sk->sk_socket->ops); - smp_store_release(&saved_tcpv6_prot, prot); - } - mutex_unlock(&tcpv6_prot_mutex); - } + mutex_lock(&tls_proto_mutex); + proto = tls_proto_find(prot); + if (proto) + goto out; - if (ip_ver == TLSV4 && - unlikely(prot != smp_load_acquire(&saved_tcpv4_prot))) { - mutex_lock(&tcpv4_prot_mutex); - if (likely(prot != saved_tcpv4_prot)) { - build_protos(tls_prots[TLSV4], prot); - build_proto_ops(tls_proto_ops[TLSV4], - sk->sk_socket->ops); - smp_store_release(&saved_tcpv4_prot, prot); - } - mutex_unlock(&tcpv4_prot_mutex); - } + proto = kzalloc(sizeof(*proto), GFP_KERNEL); + if (!proto) + goto out; + + proto->prot = prot; + refcount_set(&proto->refcnt, 2); + build_protos(proto->prots[ip_ver], prot); + build_proto_ops(proto->proto_ops[ip_ver], + sk->sk_socket->ops); + list_add_rcu(&proto->list, &tls_proto_list); + +out: + mutex_unlock(&tls_proto_mutex); + return proto; } static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], @@ -XXX,XX +XXX,XX @@ static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], static int tls_init(struct sock *sk) { + struct tls_proto *proto; struct tls_context *ctx; int rc = 0; - tls_build_proto(sk); + proto = tls_build_proto(sk); + if (!proto) + return -ENOMEM; #ifdef CONFIG_TLS_TOE - if (tls_toe_bypass(sk)) + if (tls_toe_bypass(sk, proto)) { + refcount_dec(&proto->refcnt); return 0; + } #endif /* The TLS ulp is currently supported only for TCP sockets @@ -XXX,XX +XXX,XX @@ static int tls_init(struct sock *sk) * to modify the accept implementation to clone rather then * share the ulp context. */ - if (sk->sk_state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) { + refcount_dec(&proto->refcnt); return -ENOTCONN; + } /* allocate tls context */ write_lock_bh(&sk->sk_callback_lock); - ctx = tls_ctx_create(sk); + ctx = tls_ctx_create(sk, proto); if (!ctx) { + refcount_dec(&proto->refcnt); rc = -ENOMEM; goto out; } @@ -XXX,XX +XXX,XX @@ static int __init tls_register(void) static void __exit tls_unregister(void) { + tls_proto_cleanup(); tcp_unregister_ulp(&tcp_tls_ulp_ops); tls_strp_dev_exit(); tls_device_cleanup(); diff --git a/net/tls/tls_toe.c b/net/tls/tls_toe.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_toe.c +++ b/net/tls/tls_toe.c @@ -XXX,XX +XXX,XX @@ static void tls_toe_sk_destruct(struct sock *sk) tls_ctx_free(sk, ctx); } -int tls_toe_bypass(struct sock *sk) +int tls_toe_bypass(struct sock *sk, + struct tls_proto *proto) { struct tls_toe_device *dev; struct tls_context *ctx; @@ -XXX,XX +XXX,XX @@ int tls_toe_bypass(struct sock *sk) spin_lock_bh(&device_spinlock); list_for_each_entry(dev, &device_list, dev_list) { if (dev->feature && dev->feature(dev)) { - ctx = tls_ctx_create(sk); + ctx = tls_ctx_create(sk, proto); if (!ctx) goto out; -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> To extend MPTCP support based on TCP TLS, a tls_prot_ops structure has been introduced for TLS, encapsulating TCP-specific helpers within this structure. Add registering, validating and finding functions for this structure to add, validate and find a tls_prot_ops on the global list tls_prot_ops_list. Register TCP-specific structure tls_tcp_ops in tls_init(). Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- include/net/tls.h | 19 +++++++++ net/tls/tls_main.c | 102 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/include/net/tls.h b/include/net/tls.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -XXX,XX +XXX,XX @@ struct tls_prot_info { u16 tail_size; }; +struct tls_prot_ops { + int protocol; + struct module *owner; + struct list_head list; + + int (*inq)(struct sock *sk); + int (*sendmsg_locked)(struct sock *sk, struct msghdr *msg, size_t size); + struct sk_buff *(*recv_skb)(struct sock *sk, u32 *off); + bool (*lock_is_held)(struct sock *sk); + int (*read_sock)(struct sock *sk, read_descriptor_t *desc, + sk_read_actor_t recv_actor); + void (*read_done)(struct sock *sk, size_t len); + u32 (*get_skb_seq)(struct sk_buff *skb); + __poll_t (*poll)(struct file *file, struct socket *sock, + struct poll_table_struct *wait); + bool (*epollin_ready)(const struct sock *sk); + void (*check_app_limited)(struct sock *sk); +}; + enum { TLSV4, TLSV6, diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -XXX,XX +XXX,XX @@ CHECK_CIPHER_DESC(TLS_CIPHER_ARIA_GCM_256, tls12_crypto_info_aria_gcm_256); static LIST_HEAD(tls_proto_list); static DEFINE_MUTEX(tls_proto_mutex); +static LIST_HEAD(tls_prot_ops_list); +static DEFINE_SPINLOCK(tls_prot_ops_lock); static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], const struct proto *base); @@ -XXX,XX +XXX,XX @@ static void tls_proto_cleanup(void) mutex_unlock(&tls_proto_mutex); } +static struct tls_prot_ops *tls_prot_ops_find(int protocol) +{ + struct tls_prot_ops *ops; + + list_for_each_entry_rcu(ops, &tls_prot_ops_list, list) { + if (ops->protocol == protocol) + return ops; + } + + return NULL; +} + void update_sk_prot(struct sock *sk, struct tls_context *ctx) { int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4; @@ -XXX,XX +XXX,XX @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = { .get_info_size = tls_get_info_size, }; +static int tls_validate_prot_ops(const struct tls_prot_ops *ops) +{ + if (!ops->inq || !ops->sendmsg_locked || + !ops->recv_skb || !ops->lock_is_held || + !ops->read_sock || !ops->read_done || + !ops->get_skb_seq || + !ops->poll || !ops->epollin_ready || + !ops->check_app_limited) { + pr_err("%d does not implement required ops\n", ops->protocol); + return -EINVAL; + } + + return 0; +} + +static int tls_register_prot_ops(struct tls_prot_ops *ops) +{ + int ret; + + ret = tls_validate_prot_ops(ops); + if (ret) + return ret; + + spin_lock(&tls_prot_ops_lock); + rcu_read_lock(); + if (tls_prot_ops_find(ops->protocol)) { + rcu_read_unlock(); + spin_unlock(&tls_prot_ops_lock); + return -EEXIST; + } + rcu_read_unlock(); + list_add_tail_rcu(&ops->list, &tls_prot_ops_list); + spin_unlock(&tls_prot_ops_lock); + + pr_debug("tls_prot_ops %d registered\n", ops->protocol); + return 0; +} + +static void tls_unregister_prot_ops(struct tls_prot_ops *ops) +{ + spin_lock(&tls_prot_ops_lock); + list_del_rcu(&ops->list); + synchronize_rcu(); + spin_unlock(&tls_prot_ops_lock); +} + +static struct sk_buff *tls_tcp_recv_skb(struct sock *sk, u32 *off) +{ + return tcp_recv_skb(sk, tcp_sk(sk)->copied_seq, off); +} + +static bool tls_tcp_lock_is_held(struct sock *sk) +{ + return sock_owned_by_user_nocheck(sk); +} + +static u32 tls_tcp_get_skb_seq(struct sk_buff *skb) +{ + return TCP_SKB_CB(skb)->seq; +} + +static bool tls_tcp_epollin_ready(const struct sock *sk) +{ + return tcp_epollin_ready(sk, INT_MAX); +} + +static struct tls_prot_ops tls_tcp_ops = { + .protocol = IPPROTO_TCP, + .owner = THIS_MODULE, + .inq = tcp_inq, + .sendmsg_locked = tcp_sendmsg_locked, + .recv_skb = tls_tcp_recv_skb, + .lock_is_held = tls_tcp_lock_is_held, + .read_sock = tcp_read_sock, + .read_done = tcp_read_done, + .get_skb_seq = tls_tcp_get_skb_seq, + .poll = tcp_poll, + .epollin_ready = tls_tcp_epollin_ready, + .check_app_limited = tcp_rate_check_app_limited, +}; + static int __init tls_register(void) { int err; @@ -XXX,XX +XXX,XX @@ static int __init tls_register(void) if (err) goto err_strp; + err = tls_register_prot_ops(&tls_tcp_ops); + if (err) + goto err_dev; + tcp_register_ulp(&tcp_tls_ulp_ops); return 0; +err_dev: + tls_device_cleanup(); err_strp: tls_strp_dev_exit(); err_pernet: @@ -XXX,XX +XXX,XX @@ static int __init tls_register(void) static void __exit tls_unregister(void) { tls_proto_cleanup(); + tls_unregister_prot_ops(&tls_tcp_ops); tcp_unregister_ulp(&tcp_tls_ulp_ops); tls_strp_dev_exit(); tls_device_cleanup(); -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> A pointer to struct tls_prot_ops, named 'ops', has been added to struct tls_proto. In tls_build_proto(), proto->ops is assigned either 'tls_mptcp_ops' or 'tls_tcp_ops' based on the socket protocol. Fix module reference counting bug where each socket release called module_put() without matching get for existing tls_proto. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- include/net/tls.h | 1 + net/tls/tls_main.c | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/include/net/tls.h b/include/net/tls.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -XXX,XX +XXX,XX @@ struct tls_proto { refcount_t refcnt; struct list_head list; const struct proto *prot; + const struct tls_prot_ops *ops; struct proto prots[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG]; struct proto_ops proto_ops[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG]; }; diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -XXX,XX +XXX,XX @@ static void tls_proto_cleanup(void) if (refcount_dec_and_test(&prot->refcnt)) { list_del_rcu(&prot->list); synchronize_rcu(); + module_put(prot->ops->owner); kfree(prot); } } @@ -XXX,XX +XXX,XX @@ void tls_ctx_free(struct sock *sk, struct tls_context *ctx) return; if (ctx->proto) { + module_put(ctx->proto->ops->owner); if (refcount_dec_and_test(&ctx->proto->refcnt)) { list_del_rcu(&ctx->proto->list); synchronize_rcu(); + module_put(ctx->proto->ops->owner); kfree(ctx->proto); } } @@ -XXX,XX +XXX,XX @@ static struct tls_proto *tls_build_proto(struct sock *sk) { int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4; struct proto *prot = READ_ONCE(sk->sk_prot); + struct tls_prot_ops *ops; struct tls_proto *proto; mutex_lock(&tls_proto_mutex); @@ -XXX,XX +XXX,XX @@ static struct tls_proto *tls_build_proto(struct sock *sk) if (proto) goto out; + rcu_read_lock(); + ops = tls_prot_ops_find(sk->sk_protocol); + if (!ops || !try_module_get(ops->owner)) { + rcu_read_unlock(); + goto out; + } + rcu_read_unlock(); + proto = kzalloc(sizeof(*proto), GFP_KERNEL); - if (!proto) + if (!proto) { + module_put(ops->owner); goto out; + } proto->prot = prot; + proto->ops = ops; refcount_set(&proto->refcnt, 2); build_protos(proto->prots[ip_ver], prot); build_proto_ops(proto->proto_ops[ip_ver], @@ -XXX,XX +XXX,XX @@ static int tls_init(struct sock *sk) if (!proto) return -ENOMEM; + if (!try_module_get(proto->ops->owner)) { + refcount_dec(&proto->refcnt); + return -ENOENT; + } + #ifdef CONFIG_TLS_TOE if (tls_toe_bypass(sk, proto)) { refcount_dec(&proto->refcnt); + module_put(proto->ops->owner); return 0; } #endif @@ -XXX,XX +XXX,XX @@ static int tls_init(struct sock *sk) */ if (sk->sk_state != TCP_ESTABLISHED) { refcount_dec(&proto->refcnt); + module_put(proto->ops->owner); return -ENOTCONN; } @@ -XXX,XX +XXX,XX @@ static int tls_init(struct sock *sk) ctx = tls_ctx_create(sk, proto); if (!ctx) { refcount_dec(&proto->refcnt); + module_put(proto->ops->owner); rc = -ENOMEM; goto out; } -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> The places originally calling TLS-specific helpers have now been modified to indirectly invoke them via 'ops' pointer in tls_proto. Make TLS code protocol-agnostic. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- net/tls/tls_main.c | 10 ++++++---- net/tls/tls_strp.c | 33 ++++++++++++++++++++++----------- net/tls/tls_sw.c | 7 +++++-- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -XXX,XX +XXX,XX @@ int tls_push_sg(struct sock *sk, ctx->splicing_pages = true; while (1) { /* is sending application-limited? */ - tcp_rate_check_app_limited(sk); + ctx->proto->ops->check_app_limited(sk); p = sg_page(sg); retry: bvec_set_page(&bvec, p, size, offset); iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - ret = tcp_sendmsg_locked(sk, &msg, size); + ret = ctx->proto->ops->sendmsg_locked(sk, &msg, size); if (ret != size) { if (ret > 0) { @@ -XXX,XX +XXX,XX @@ static __poll_t tls_sk_poll(struct file *file, struct socket *sock, u8 shutdown; int state; - mask = tcp_poll(file, sock, wait); + tls_ctx = tls_get_ctx(sk); + if (!tls_ctx || !tls_ctx->proto || !tls_ctx->proto->ops) + return 0; + mask = tls_ctx->proto->ops->poll(file, sock, wait); state = inet_sk_state_load(sk); shutdown = READ_ONCE(sk->sk_shutdown); if (unlikely(state != TCP_ESTABLISHED || shutdown & RCV_SHUTDOWN)) return mask; - tls_ctx = tls_get_ctx(sk); ctx = tls_sw_ctx_rx(tls_ctx); psock = sk_psock_get(sk); diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_strp.c +++ b/net/tls/tls_strp.c @@ -XXX,XX +XXX,XX @@ struct sk_buff *tls_strp_msg_detach(struct tls_sw_context_rx *ctx) int tls_strp_msg_cow(struct tls_sw_context_rx *ctx) { struct tls_strparser *strp = &ctx->strp; + struct tls_context *tls_ctx; struct sk_buff *skb; if (strp->copy_mode) @@ -XXX,XX +XXX,XX @@ int tls_strp_msg_cow(struct tls_sw_context_rx *ctx) tls_strp_anchor_free(strp); strp->anchor = skb; - tcp_read_done(strp->sk, strp->stm.full_len); + tls_ctx = tls_get_ctx(strp->sk); + tls_ctx->proto->ops->read_done(strp->sk, strp->stm.full_len); strp->copy_mode = 1; return 0; @@ -XXX,XX +XXX,XX @@ static int tls_strp_copyin(read_descriptor_t *desc, struct sk_buff *in_skb, static int tls_strp_read_copyin(struct tls_strparser *strp) { + struct tls_context *ctx = tls_get_ctx(strp->sk); read_descriptor_t desc; desc.arg.data = strp; @@ -XXX,XX +XXX,XX @@ static int tls_strp_read_copyin(struct tls_strparser *strp) desc.count = 1; /* give more than one skb per call */ /* sk should be locked here, so okay to do read_sock */ - tcp_read_sock(strp->sk, &desc, tls_strp_copyin); + ctx->proto->ops->read_sock(strp->sk, &desc, tls_strp_copyin); return desc.error; } static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort) { + struct tls_context *ctx = tls_get_ctx(strp->sk); struct skb_shared_info *shinfo; struct page *page; int need_spc, len; @@ -XXX,XX +XXX,XX @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort) * to read the data out. Otherwise the connection will stall. * Without pressure threshold of INT_MAX will never be ready. */ - if (likely(qshort && !tcp_epollin_ready(strp->sk, INT_MAX))) + if (likely(qshort && !ctx->proto->ops->epollin_ready(strp->sk))) return 0; shinfo = skb_shinfo(strp->anchor); @@ -XXX,XX +XXX,XX @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort) static bool tls_strp_check_queue_ok(struct tls_strparser *strp) { unsigned int len = strp->stm.offset + strp->stm.full_len; + struct tls_context *ctx = tls_get_ctx(strp->sk); struct sk_buff *first, *skb; u32 seq; first = skb_shinfo(strp->anchor)->frag_list; skb = first; - seq = TCP_SKB_CB(first)->seq; + seq = ctx->proto->ops->get_skb_seq(first); /* Make sure there's no duplicate data in the queue, * and the decrypted status matches. @@ -XXX,XX +XXX,XX @@ static bool tls_strp_check_queue_ok(struct tls_strparser *strp) len -= skb->len; skb = skb->next; - if (TCP_SKB_CB(skb)->seq != seq) + if (ctx->proto->ops->get_skb_seq(skb) != seq) return false; if (skb_cmp_decrypted(first, skb)) return false; @@ -XXX,XX +XXX,XX @@ static bool tls_strp_check_queue_ok(struct tls_strparser *strp) static void tls_strp_load_anchor_with_queue(struct tls_strparser *strp, int len) { - struct tcp_sock *tp = tcp_sk(strp->sk); + struct tls_context *ctx = tls_get_ctx(strp->sk); struct sk_buff *first; u32 offset; - first = tcp_recv_skb(strp->sk, tp->copied_seq, &offset); + first = ctx->proto->ops->recv_skb(strp->sk, &offset); if (WARN_ON_ONCE(!first)) return; @@ -XXX,XX +XXX,XX @@ static void tls_strp_load_anchor_with_queue(struct tls_strparser *strp, int len) bool tls_strp_msg_load(struct tls_strparser *strp, bool force_refresh) { + struct tls_context *ctx = tls_get_ctx(strp->sk); struct strp_msg *rxm; struct tls_msg *tlm; @@ -XXX,XX +XXX,XX @@ bool tls_strp_msg_load(struct tls_strparser *strp, bool force_refresh) DEBUG_NET_WARN_ON_ONCE(!strp->stm.full_len); if (!strp->copy_mode && force_refresh) { - if (unlikely(tcp_inq(strp->sk) < strp->stm.full_len)) { + if (unlikely(ctx->proto->ops->inq(strp->sk) < strp->stm.full_len)) { WRITE_ONCE(strp->msg_ready, 0); memset(&strp->stm, 0, sizeof(strp->stm)); return false; @@ -XXX,XX +XXX,XX @@ bool tls_strp_msg_load(struct tls_strparser *strp, bool force_refresh) /* Called with lock held on lower socket */ static int tls_strp_read_sock(struct tls_strparser *strp) { + struct tls_context *ctx = tls_get_ctx(strp->sk); int sz, inq; - inq = tcp_inq(strp->sk); + inq = ctx->proto->ops->inq(strp->sk); if (inq < 1) return 0; @@ -XXX,XX +XXX,XX @@ void tls_strp_check_rcv(struct tls_strparser *strp) /* Lower sock lock held */ void tls_strp_data_ready(struct tls_strparser *strp) { + struct tls_context *ctx = tls_get_ctx(strp->sk); + /* This check is needed to synchronize with do_tls_strp_work. * do_tls_strp_work acquires a process lock (lock_sock) whereas * the lock held here is bh_lock_sock. The two locks can be @@ -XXX,XX +XXX,XX @@ void tls_strp_data_ready(struct tls_strparser *strp) * allows a thread in BH context to safely check if the process * lock is held. In this case, if the lock is held, queue work. */ - if (sock_owned_by_user_nocheck(strp->sk)) { + if (ctx->proto->ops->lock_is_held(strp->sk)) { queue_work(tls_strp_wq, &strp->work); return; } @@ -XXX,XX +XXX,XX @@ static void tls_strp_work(struct work_struct *w) void tls_strp_msg_done(struct tls_strparser *strp) { + struct tls_context *ctx = tls_get_ctx(strp->sk); + WARN_ON(!strp->stm.full_len); if (likely(!strp->copy_mode)) - tcp_read_done(strp->sk, strp->stm.full_len); + ctx->proto->ops->read_done(strp->sk, strp->stm.full_len); else tls_strp_flush_anchor_copy(strp); diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -XXX,XX +XXX,XX @@ tls_read_flush_backlog(struct sock *sk, struct tls_prot_info *prot, size_t len_left, size_t decrypted, ssize_t done, size_t *flushed_at) { + struct tls_context *tls_ctx = tls_get_ctx(sk); size_t max_rec; if (len_left <= decrypted) return false; max_rec = prot->overhead_size - prot->tail_size + TLS_MAX_PAYLOAD_SIZE; - if (done - *flushed_at < SZ_128K && tcp_inq(sk) > max_rec) + if (done - *flushed_at < SZ_128K && tls_ctx->proto->ops->inq(sk) > max_rec) return false; *flushed_at = done; @@ -XXX,XX +XXX,XX @@ int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb) size_t cipher_overhead; size_t data_len = 0; int ret; + u32 seq; /* Verify that we have a full TLS header, or wait for more data */ if (strp->stm.offset + prot->prepend_size > skb->len) @@ -XXX,XX +XXX,XX @@ int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb) goto read_failure; } + seq = tls_ctx->proto->ops->get_skb_seq(skb); tls_device_rx_resync_new_rec(strp->sk, data_len + TLS_HEADER_SIZE, - TCP_SKB_CB(skb)->seq + strp->stm.offset); + seq + strp->stm.offset); return data_len + TLS_HEADER_SIZE; read_failure: -- 2.51.0
From: Gang Yan <yangang@kylinos.cn> This patch makes mptcp_check_readable() aligned with TCP, and renames it to mptcp_stream_is_readable(). It will be used in the case of KTLS, because 'prot' will be modified, tls_sw_sock_is_readable() is expected to be called from prot->sock_is_readable(). Co-developed-by: Geliang Tang <geliang@kernel.org> Signed-off-by: Geliang Tang <geliang@kernel.org> Signed-off-by: Gang Yan <yangang@kylinos.cn> --- net/mptcp/protocol.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -XXX,XX +XXX,XX @@ void __mptcp_unaccepted_force_close(struct sock *sk) __mptcp_destroy_sock(sk); } -static __poll_t mptcp_check_readable(struct sock *sk) +static bool mptcp_stream_is_readable(struct sock *sk) { - return mptcp_epollin_ready(sk) ? EPOLLIN | EPOLLRDNORM : 0; + if (mptcp_epollin_ready(sk)) + return true; + return sk_is_readable(sk); } static void mptcp_check_listen_stop(struct sock *sk) @@ -XXX,XX +XXX,XX @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock, mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP; if (state != TCP_SYN_SENT && state != TCP_SYN_RECV) { - mask |= mptcp_check_readable(sk); + if (mptcp_stream_is_readable(sk)) + mask |= EPOLLIN | EPOLLRDNORM; if (shutdown & SEND_SHUTDOWN) mask |= EPOLLOUT | EPOLLWRNORM; else -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> This patch implements the MPTCP-specific struct tls_prot_ops, named 'tls_mptcp_ops'. Note that there is a slight difference between mptcp_inq() and mptcp_inq_hint(), it does not return 1 when the socket is closed or shut down; instead, it returns 0. Otherwise, it would break the condition "inq < 1" in tls_strp_read_sock(). Passing an MPTCP socket to tcp_sock_rate_check_app_limited() can trigger a crash. Here, an MPTCP version of check_app_limited() is implemented, which calls tcp_sock_rate_check_app_limited() for each subflow. When MPTCP implements lock_is_held interface, it not only checks sock_owned_by_user_nocheck(sk) as TCP does, but also needs to check whether the MPTCP data lock is held. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- include/net/mptcp.h | 2 + include/net/tcp.h | 1 + net/ipv4/tcp.c | 9 +++- net/mptcp/protocol.c | 108 ++++++++++++++++++++++++++++++++++++++++--- net/mptcp/protocol.h | 1 + net/tls/tls_main.c | 13 ++++++ 6 files changed, 126 insertions(+), 8 deletions(-) diff --git a/include/net/mptcp.h b/include/net/mptcp.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -XXX,XX +XXX,XX @@ struct mptcp_pm_ops { void (*release)(struct mptcp_sock *msk); } ____cacheline_aligned_in_smp; +extern struct tls_prot_ops tls_mptcp_ops; + #ifdef CONFIG_MPTCP void mptcp_init(void); diff --git a/include/net/tcp.h b/include/net/tcp.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -XXX,XX +XXX,XX @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize) /* tcp.c */ void tcp_get_info(struct sock *, struct tcp_info *); +void tcp_sock_rate_check_app_limited(struct tcp_sock *tp); void tcp_rate_check_app_limited(struct sock *sk); /* Read 'sendfile()'-style from a TCP socket */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index XXXXXXX..XXXXXXX 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -XXX,XX +XXX,XX @@ int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *copied, } /* If a gap is detected between sends, mark the socket application-limited. */ -void tcp_rate_check_app_limited(struct sock *sk) +void tcp_sock_rate_check_app_limited(struct tcp_sock *tp) { - struct tcp_sock *tp = tcp_sk(sk); + struct sock *sk = (struct sock *)tp; if (/* We have less than one packet to send. */ tp->write_seq - tp->snd_nxt < tp->mss_cache && @@ -XXX,XX +XXX,XX @@ void tcp_rate_check_app_limited(struct sock *sk) tp->app_limited = (tp->delivered + tcp_packets_in_flight(tp)) ? : 1; } + +void tcp_rate_check_app_limited(struct sock *sk) +{ + tcp_sock_rate_check_app_limited(tcp_sk(sk)); +} EXPORT_SYMBOL_GPL(tcp_rate_check_app_limited); int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -XXX,XX +XXX,XX @@ #include <net/mptcp.h> #include <net/hotdata.h> #include <net/xfrm.h> +#include <net/tls.h> #include <asm/ioctls.h> #include "protocol.h" #include "mib.h" -static unsigned int mptcp_inq_hint(const struct sock *sk); +static unsigned int mptcp_inq_hint(struct sock *sk); #define CREATE_TRACE_POINTS #include <trace/events/mptcp.h> @@ -XXX,XX +XXX,XX @@ static void mptcp_rps_record_subflows(const struct mptcp_sock *msk) } } -static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) +static int mptcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t len) { struct mptcp_sock *msk = mptcp_sk(sk); struct page_frag *pfrag; @@ -XXX,XX +XXX,XX @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) msg->msg_flags &= MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_FASTOPEN | MSG_EOR; - lock_sock(sk); - mptcp_rps_record_subflows(msk); if (unlikely(inet_test_bit(DEFER_CONNECT, sk) || @@ -XXX,XX +XXX,XX @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) } out: - release_sock(sk); return copied; do_error: @@ -XXX,XX +XXX,XX @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) goto out; } +static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) +{ + int ret; + + lock_sock(sk); + ret = mptcp_sendmsg_locked(sk, msg, len); + release_sock(sk); + + return ret; +} + static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied); static void mptcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb) @@ -XXX,XX +XXX,XX @@ static bool mptcp_move_skbs(struct sock *sk) return enqueued; } -static unsigned int mptcp_inq_hint(const struct sock *sk) +static int mptcp_inq(struct sock *sk) { const struct mptcp_sock *msk = mptcp_sk(sk); const struct sk_buff *skb; @@ -XXX,XX +XXX,XX @@ static unsigned int mptcp_inq_hint(const struct sock *sk) return (unsigned int)hint_val; } + return 0; +} + +static unsigned int mptcp_inq_hint(struct sock *sk) +{ + unsigned int inq = mptcp_inq(sk); + + if (inq) + return inq; + if (sk->sk_state == TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN)) return 1; @@ -XXX,XX +XXX,XX @@ int __init mptcp_proto_v6_init(void) return err; } #endif + +static bool mptcp_lock_is_held(struct sock *sk) +{ + return sock_owned_by_user_nocheck(sk) || + mptcp_data_is_locked(sk); +} + +static void mptcp_read_done(struct sock *sk, size_t len) +{ + struct mptcp_sock *msk = mptcp_sk(sk); + struct sk_buff *skb; + size_t left; + u32 offset; + + msk_owned_by_me(msk); + + if (sk->sk_state == TCP_LISTEN) + return; + + left = len; + while (left && (skb = mptcp_recv_skb(sk, &offset)) != NULL) { + int used; + + used = min_t(size_t, skb->len - offset, left); + msk->bytes_consumed += used; + MPTCP_SKB_CB(skb)->offset += used; + MPTCP_SKB_CB(skb)->map_seq += used; + left -= used; + + if (skb->len > offset + used) + break; + + mptcp_eat_recv_skb(sk, skb); + } + + mptcp_rcv_space_adjust(msk, len - left); + + /* Clean up data we have read: This will do ACK frames. */ + if (left != len) + mptcp_cleanup_rbuf(msk, len - left); +} + +static u32 mptcp_get_skb_seq(struct sk_buff *skb) +{ + return MPTCP_SKB_CB(skb)->map_seq - MPTCP_SKB_CB(skb)->offset; +} + +static void mptcp_check_app_limited(struct sock *sk) +{ + struct mptcp_sock *msk = mptcp_sk(sk); + struct mptcp_subflow_context *subflow; + + mptcp_for_each_subflow(msk, subflow) { + struct sock *ssk = mptcp_subflow_tcp_sock(subflow); + bool slow; + + slow = lock_sock_fast(ssk); + tcp_sock_rate_check_app_limited(tcp_sk(ssk)); + unlock_sock_fast(ssk, slow); + } +} + +struct tls_prot_ops tls_mptcp_ops = { + .protocol = IPPROTO_MPTCP, + .owner = THIS_MODULE, + .inq = mptcp_inq, + .sendmsg_locked = mptcp_sendmsg_locked, + .recv_skb = mptcp_recv_skb, + .lock_is_held = mptcp_lock_is_held, + .read_sock = mptcp_read_sock, + .read_done = mptcp_read_done, + .get_skb_seq = mptcp_get_skb_seq, + .poll = mptcp_poll, + .epollin_ready = mptcp_epollin_ready, + .check_app_limited = mptcp_check_app_limited, +}; +EXPORT_SYMBOL(tls_mptcp_ops); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ struct mptcp_sock { #define mptcp_data_lock(sk) spin_lock_bh(&(sk)->sk_lock.slock) #define mptcp_data_unlock(sk) spin_unlock_bh(&(sk)->sk_lock.slock) +#define mptcp_data_is_locked(sk) spin_is_locked(&(sk)->sk_lock.slock) #define mptcp_for_each_subflow(__msk, __subflow) \ list_for_each_entry(__subflow, &((__msk)->conn_list), node) diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -XXX,XX +XXX,XX @@ static int __init tls_register(void) if (err) goto err_dev; +#ifdef CONFIG_MPTCP + err = tls_register_prot_ops(&tls_mptcp_ops); + if (err) + goto err_prot_ops; +#endif + tcp_register_ulp(&tcp_tls_ulp_ops); return 0; +#ifdef CONFIG_MPTCP +err_prot_ops: + tls_unregister_prot_ops(&tls_tcp_ops); +#endif err_dev: tls_device_cleanup(); err_strp: @@ -XXX,XX +XXX,XX @@ static int __init tls_register(void) static void __exit tls_unregister(void) { tls_proto_cleanup(); +#ifdef CONFIG_MPTCP + tls_unregister_prot_ops(&tls_mptcp_ops); +#endif tls_unregister_prot_ops(&tls_tcp_ops); tcp_unregister_ulp(&tcp_tls_ulp_ops); tls_strp_dev_exit(); -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> MPTCP TLS hardware offload is not yet implemented. Return -EOPNOTSUPP when attempting to enable device offload on MPTCP sockets. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- net/tls/tls_device.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -XXX,XX +XXX,XX @@ int tls_set_device_offload(struct sock *sk) ctx = tls_get_ctx(sk); prot = &ctx->prot_info; + if (sk->sk_protocol == IPPROTO_MPTCP) + return -EOPNOTSUPP; + if (ctx->priv_ctx_tx) return -EEXIST; @@ -XXX,XX +XXX,XX @@ int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx) struct net_device *netdev; int rc = 0; + if (sk->sk_protocol == IPPROTO_MPTCP) + return -EOPNOTSUPP; + if (ctx->crypto_recv.info.version != TLS_1_2_VERSION) return -EOPNOTSUPP; -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> This patch extracts TCP_ULP getsockopt operation into a tcp_sock_get_ulp() helper so that it can also be used in MPTCP. TCP_ULP was obtained by calling mptcp_getsockopt_first_sf_only() to get ULP of the first subflow. Now that the mechanism has changed, a new helper mptcp_getsockopt_tcp_ulp() is added to get ULP of msk. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- include/linux/tcp.h | 1 + net/ipv4/tcp.c | 36 ++++++++++++++++++++++-------------- net/mptcp/sockopt.c | 18 ++++++++++++++++++ 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index XXXXXXX..XXXXXXX 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -XXX,XX +XXX,XX @@ void tcp_sock_set_quickack(struct sock *sk, int val); int tcp_sock_set_syncnt(struct sock *sk, int val); int tcp_sock_set_user_timeout(struct sock *sk, int val); int tcp_sock_set_maxseg(struct sock *sk, int val); +int tcp_sock_get_ulp(struct sock *sk, sockptr_t optval, sockptr_t optlen); static inline bool dst_tcp_usec_ts(const struct dst_entry *dst) { diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index XXXXXXX..XXXXXXX 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -XXX,XX +XXX,XX @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, return stats; } +int tcp_sock_get_ulp(struct sock *sk, sockptr_t optval, sockptr_t optlen) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + int len; + + if (copy_from_sockptr(&len, optlen, sizeof(int))) + return -EFAULT; + len = min_t(unsigned int, len, TCP_ULP_NAME_MAX); + if (!icsk->icsk_ulp_ops) { + len = 0; + if (copy_to_sockptr(optlen, &len, sizeof(int))) + return -EFAULT; + return 0; + } + if (copy_to_sockptr(optlen, &len, sizeof(int))) + return -EFAULT; + if (copy_to_sockptr(optval, icsk->icsk_ulp_ops->name, len)) + return -EFAULT; + return 0; +} + int do_tcp_getsockopt(struct sock *sk, int level, int optname, sockptr_t optval, sockptr_t optlen) { @@ -XXX,XX +XXX,XX @@ int do_tcp_getsockopt(struct sock *sk, int level, return 0; case TCP_ULP: - if (copy_from_sockptr(&len, optlen, sizeof(int))) - return -EFAULT; - len = min_t(unsigned int, len, TCP_ULP_NAME_MAX); - if (!icsk->icsk_ulp_ops) { - len = 0; - if (copy_to_sockptr(optlen, &len, sizeof(int))) - return -EFAULT; - return 0; - } - if (copy_to_sockptr(optlen, &len, sizeof(int))) - return -EFAULT; - if (copy_to_sockptr(optval, icsk->icsk_ulp_ops->name, len)) - return -EFAULT; - return 0; + return tcp_sock_get_ulp(sk, optval, optlen); case TCP_FASTOPEN_KEY: { u64 key[TCP_FASTOPEN_KEY_BUF_LENGTH / sizeof(u64)]; diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -XXX,XX +XXX,XX @@ static int mptcp_put_int_option(struct mptcp_sock *msk, char __user *optval, return 0; } +static int mptcp_getsockopt_tcp_ulp(struct sock *sk, char __user *optval, + int __user *optlen) +{ + int ret, len; + + if (copy_from_sockptr(&len, USER_SOCKPTR(optlen), sizeof(int))) + return -EFAULT; + + if (len < 0) + return -EINVAL; + + lock_sock(sk); + ret = tcp_sock_get_ulp(sk, USER_SOCKPTR(optval), USER_SOCKPTR(optlen)); + release_sock(sk); + return ret; +} + static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname, char __user *optval, int __user *optlen) { @@ -XXX,XX +XXX,XX @@ static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname, switch (optname) { case TCP_ULP: + return mptcp_getsockopt_tcp_ulp(sk, optval, optlen); case TCP_CONGESTION: case TCP_INFO: case TCP_CC_INFO: -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> Allow MPTCP sockets to set the TCP_ULP socket option to enable TLS. Add mptcp_setsockopt_tcp_ulp() which validates the socket state (must not be CLOSE or LISTEN), only accepts "tls" as the ULP name, and then calls tcp_set_ulp(). Include TCP_ULP in the list of supported options in supported_sockopt(), and handle it in setsockopt_sol_tcp() instead of returning -EOPNOTSUPP. Call tcp_cleanup_ulp() in mptcp_destroy_common() to release ULP module's reference count. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- net/mptcp/protocol.c | 1 + net/mptcp/sockopt.c | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -XXX,XX +XXX,XX @@ static void mptcp_destroy(struct sock *sk) /* allow the following to close even the initial subflow */ msk->free_first = 1; mptcp_destroy_common(msk); + tcp_cleanup_ulp(sk); sk_sockets_allocated_dec(sk); } diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -XXX,XX +XXX,XX @@ #include <net/protocol.h> #include <net/tcp.h> #include <net/mptcp.h> +#include <net/tls.h> #include "protocol.h" #define MIN_INFO_OPTLEN_SIZE 16 @@ -XXX,XX +XXX,XX @@ static bool mptcp_supported_sockopt(int level, int optname) case TCP_FASTOPEN_CONNECT: case TCP_FASTOPEN_KEY: case TCP_FASTOPEN_NO_COOKIE: + case TCP_ULP: return true; } @@ -XXX,XX +XXX,XX @@ static int mptcp_setsockopt_all_sf(struct mptcp_sock *msk, int level, return ret; } +static int mptcp_setsockopt_tcp_ulp(struct sock *sk, sockptr_t optval, + unsigned int optlen) +{ + char name[TCP_ULP_NAME_MAX]; + int err = 0; + size_t len; + int val; + + if (optlen < 1) + return -EINVAL; + + len = min_t(long, TCP_ULP_NAME_MAX - 1, optlen); + val = strncpy_from_sockptr(name, optval, len); + if (val < 0) + return -EFAULT; + name[val] = 0; + + if (strcmp(name, "tls")) + return -EOPNOTSUPP; + + sockopt_lock_sock(sk); + if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) { + err = -ENOTCONN; + goto out; + } + err = tcp_set_ulp(sk, name); +out: + sockopt_release_sock(sk); + return err; +} + static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname, sockptr_t optval, unsigned int optlen) { @@ -XXX,XX +XXX,XX @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname, switch (optname) { case TCP_ULP: - return -EOPNOTSUPP; + return mptcp_setsockopt_tcp_ulp(sk, optval, optlen); case TCP_CONGESTION: return mptcp_setsockopt_sol_tcp_congestion(msk, optval, optlen); case TCP_DEFER_ACCEPT: -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> With KTLS being implemented, "tls" should no longer be used in sock_test_tcpulp(), it breaks mptcp_connect.sh tests. Another ULP name, "espintcp", is set instead in this patch. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/mptcp/mptcp_connect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.c +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c @@ -XXX,XX +XXX,XX @@ static void sock_test_tcpulp(int sock, int proto, unsigned int line) if (buflen > 0) { if (strcmp(buf, "mptcp") != 0) xerror("unexpected ULP '%s' for proto %d at line %u", buf, proto, line); - ret = do_ulp_so(sock, "tls"); + ret = do_ulp_so(sock, "espintcp"); if (ret == 0) X("setsockopt"); } else if (proto == IPPROTO_MPTCP) { - ret = do_ulp_so(sock, "tls"); + ret = do_ulp_so(sock, "espintcp"); if (ret != -1) X("setsockopt"); } -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> To enable easy MPTCP socket creation in MPTCP TLS tests, two protocol parameters (cli_proto and srv_proto) have been added to ulp_sock_pair(). These are passed as third arguments of socket(): 0 creates TCP sockets, IPPROTO_MPTCP creates MPTCP sockets. A new variant "mptcp" is added both in FIXTURE_VARIANT(tls) to control whether to create MPTCP sockets or not for tests. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/tls.c | 44 +++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -XXX,XX +XXX,XX @@ #define TLS_PAYLOAD_MAX_LEN 16384 #define SOL_TLS 282 +#ifndef IPPROTO_MPTCP +#define IPPROTO_MPTCP 262 +#endif + static int fips_enabled; struct tls_crypto_info_keys { @@ -XXX,XX +XXX,XX @@ static void memrnd(void *s, size_t n) *byte++ = rand(); } -static void ulp_sock_pair(struct __test_metadata *_metadata, - int *fd, int *cfd, bool *notls) +static void __ulp_sock_pair(struct __test_metadata *_metadata, + int *fd, int *cfd, bool *notls, + int cli_proto, int srv_proto) { struct sockaddr_in addr; socklen_t len; @@ -XXX,XX +XXX,XX @@ static void ulp_sock_pair(struct __test_metadata *_metadata, addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = 0; - *fd = socket(AF_INET, SOCK_STREAM, 0); - sfd = socket(AF_INET, SOCK_STREAM, 0); + *fd = socket(AF_INET, SOCK_STREAM, cli_proto); + sfd = socket(AF_INET, SOCK_STREAM, srv_proto); ret = bind(sfd, &addr, sizeof(addr)); ASSERT_EQ(ret, 0); @@ -XXX,XX +XXX,XX @@ static void ulp_sock_pair(struct __test_metadata *_metadata, ASSERT_EQ(ret, 0); } +static void ulp_sock_pair(struct __test_metadata *_metadata, + int *fd, int *cfd, bool *notls) +{ + __ulp_sock_pair(_metadata, fd, cfd, notls, 0, 0); +} + /* Produce a basic cmsg */ static int tls_send_cmsg(int fd, unsigned char record_type, void *data, size_t len, int flags) @@ -XXX,XX +XXX,XX @@ FIXTURE_VARIANT(tls) uint16_t tls_version; uint16_t cipher_type; bool nopad, fips_non_compliant; + bool mptcp; }; FIXTURE_VARIANT_ADD(tls, 12_aes_gcm) @@ -XXX,XX +XXX,XX @@ FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_256) .cipher_type = TLS_CIPHER_ARIA_GCM_256, }; +static bool is_mptcp_enable(struct __test_metadata *_metadata) +{ + char buf[16] = { 0 }; + ssize_t n; + int fd; + + fd = open("/proc/sys/net/mptcp/enabled", O_RDONLY); + if (fd < 0) + return false; + + n = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (n <= 0) + return false; + return (atoi(buf) == 1); +} + FIXTURE_SETUP(tls) { struct tls_crypto_info_keys tls12; @@ -XXX,XX +XXX,XX @@ FIXTURE_SETUP(tls) if (fips_enabled && variant->fips_non_compliant) SKIP(return, "Unsupported cipher in FIPS mode"); + if (variant->mptcp && !is_mptcp_enable(_metadata)) + SKIP(return, "no MPTCP support"); + tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 0); - ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls); + __ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls, + variant->mptcp ? IPPROTO_MPTCP : 0, + variant->mptcp ? IPPROTO_MPTCP : 0); if (self->notls) return; -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> MPTCP requires longer timeouts in pollin test due to subflow establishment delays and slower state transitions. Increase timeout values to prevent false failures: # RUN tls.13_sm4_ccm_mptcp.pollin ... # tls.c:1411:pollin:Expected poll(&fd, 1, 20) (0) == 1 (1) # tls.c:1412:pollin:Expected fd.revents & POLLIN (0) == 1 (1) # pollin: Test failed # FAIL tls.13_sm4_ccm_mptcp.pollin not ok 357 tls.13_sm4_ccm_mptcp.pollin Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/tls.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -XXX,XX +XXX,XX @@ TEST_F(tls, bidir) TEST_F(tls, pollin) { + int timeout = variant->mptcp ? 100 : 20; char const *test_str = "test_poll"; struct pollfd fd = { 0, 0, 0 }; char buf[10]; @@ -XXX,XX +XXX,XX @@ TEST_F(tls, pollin) fd.fd = self->cfd; fd.events = POLLIN; - EXPECT_EQ(poll(&fd, 1, 20), 1); + EXPECT_EQ(poll(&fd, 1, timeout), 1); EXPECT_EQ(fd.revents & POLLIN, 1); EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_WAITALL), send_len); /* Test timing out */ - EXPECT_EQ(poll(&fd, 1, 20), 0); + EXPECT_EQ(poll(&fd, 1, timeout), 0); } TEST_F(tls, poll_wait) -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> Increase the data size in nonblocking tests to accommodate MPTCP's multi-subflow behavior and ensure sufficient data for testing, avoiding the following errors: # RUN tls.12_aria_gcm_mptcp.nonblocking ... # tls.c:1534:nonblocking:Expected 0 (0) != eagain (0) # nonblocking: Test failed Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/tls.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -XXX,XX +XXX,XX @@ TEST_F(tls, nonblocking) int flags; int res; + if (variant->mptcp) + data *= 4; + flags = fcntl(self->fd, F_GETFL, 0); fcntl(self->fd, F_SETFL, flags | O_NONBLOCK); fcntl(self->cfd, F_SETFL, flags | O_NONBLOCK); -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> In shutdown_reuse tests, add a delay after shutdown to wait for MPTCP sockets to reach TCP_CLOSE state before reuse via bind(), avoiding the following errors: # RUN tls.12_aes_gcm_mptcp.shutdown_reuse ... # tls.c:1790:shutdown_reuse:Expected ret (-1) == 0 (0) # shutdown_reuse: Test failed # FAIL tls.12_aes_gcm_mptcp.shutdown_reuse not ok 14 tls.12_aes_gcm_mptcp.shutdown_reuse # RUN tls.13_aes_gcm_mptcp.shutdown_reuse ... # tls.c:1790:shutdown_reuse:Expected ret (-1) == 0 (0) # shutdown_reuse: Test failed # FAIL tls.13_aes_gcm_mptcp.shutdown_reuse not ok 15 tls.13_aes_gcm_mptcp.shutdown_reuse # RUN tls.12_chacha_mptcp.shutdown_reuse ... # OK tls.12_chacha_mptcp.shutdown_reuse ok 16 tls.12_chacha_mptcp.shutdown_reuse # RUN tls.13_chacha_mptcp.shutdown_reuse ... # OK tls.13_chacha_mptcp.shutdown_reuse ok 17 tls.13_chacha_mptcp.shutdown_reuse # RUN tls.13_sm4_gcm_mptcp.shutdown_reuse ... # tls.c:1790:shutdown_reuse:Expected ret (-1) == 0 (0) # shutdown_reuse: Test failed # FAIL tls.13_sm4_gcm_mptcp.shutdown_reuse not ok 18 tls.13_sm4_gcm_mptcp.shutdown_reuse This TCP_CLOSE check is just for MPTCP, because it should not slow down plain TCP tests. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/tls.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -XXX,XX +XXX,XX @@ #define IPPROTO_MPTCP 262 #endif +#ifndef TCP_CLOSE +#define TCP_CLOSE 7 +#endif + static int fips_enabled; struct tls_crypto_info_keys { @@ -XXX,XX +XXX,XX @@ TEST_F(tls, shutdown_unsent) shutdown(self->cfd, SHUT_RDWR); } +static bool wait_for_tcp_close(struct __test_metadata *_metadata, + int fd, int max) +{ + struct tcp_info info; + socklen_t len; + int i, ret; + + for (i = 0; i < max; i++) { + len = sizeof(info); + ret = getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, &len); + ASSERT_EQ(ret, 0); + if (info.tcpi_state == TCP_CLOSE) + return true; + usleep(1000); + } + + return false; +} + TEST_F(tls, shutdown_reuse) { struct sockaddr_in addr; @@ -XXX,XX +XXX,XX @@ TEST_F(tls, shutdown_reuse) shutdown(self->cfd, SHUT_RDWR); close(self->cfd); + if (variant->mptcp) + EXPECT_TRUE(wait_for_tcp_close(_metadata, self->fd, 1000)); + addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = 0; -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> This patch introduces MPTCP test cases for the TLS fixture. These "mptcp" variants are configured to create MPTCP sockets specifically for MPTCP TLS testing purposes. The default limit of 1024 for file descriptor values is too low for the newly added MPTCP tests, causing accept() to fail when the fd number exceeds 1024. Raise the limit to 4096 to avoid test failures. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/tls.c | 96 +++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -XXX,XX +XXX,XX @@ FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_256) .cipher_type = TLS_CIPHER_ARIA_GCM_256, }; +FIXTURE_VARIANT_ADD(tls, 12_aes_gcm_mptcp) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_128, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_aes_gcm_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_128, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 12_chacha_mptcp) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_CHACHA20_POLY1305, + .fips_non_compliant = true, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_chacha_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_CHACHA20_POLY1305, + .fips_non_compliant = true, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_sm4_gcm_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_SM4_GCM, + .fips_non_compliant = true, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_sm4_ccm_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_SM4_CCM, + .fips_non_compliant = true, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 12_aes_ccm_mptcp) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_AES_CCM_128, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_aes_ccm_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_AES_CCM_128, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 12_aes_gcm_256_mptcp) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_256, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_aes_gcm_256_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_256, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_nopad_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_128, + .nopad = true, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_mptcp) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_ARIA_GCM_128, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_256_mptcp) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_ARIA_GCM_256, + .mptcp = true, +}; + static bool is_mptcp_enable(struct __test_metadata *_metadata) { char buf[16] = { 0 }; -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> The mptcp tests for tls.c is available now, this patch adds mptcp_tls.sh to test it in the MPTCP CI by default. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/mptcp/.gitignore | 1 + tools/testing/selftests/net/mptcp/Makefile | 2 + tools/testing/selftests/net/mptcp/config | 5 ++ .../testing/selftests/net/mptcp/mptcp_tls.sh | 62 +++++++++++++++++++ tools/testing/selftests/net/mptcp/tls.c | 1 + 5 files changed, 71 insertions(+) create mode 100755 tools/testing/selftests/net/mptcp/mptcp_tls.sh create mode 120000 tools/testing/selftests/net/mptcp/tls.c diff --git a/tools/testing/selftests/net/mptcp/.gitignore b/tools/testing/selftests/net/mptcp/.gitignore index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/mptcp/.gitignore +++ b/tools/testing/selftests/net/mptcp/.gitignore @@ -XXX,XX +XXX,XX @@ mptcp_diag mptcp_inq mptcp_sockopt pm_nl_ctl +tls *.pcap diff --git a/tools/testing/selftests/net/mptcp/Makefile b/tools/testing/selftests/net/mptcp/Makefile index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/mptcp/Makefile +++ b/tools/testing/selftests/net/mptcp/Makefile @@ -XXX,XX +XXX,XX @@ TEST_PROGS := \ mptcp_connect_splice.sh \ mptcp_join.sh \ mptcp_sockopt.sh \ + mptcp_tls.sh \ pm_netlink.sh \ simult_flows.sh \ userspace_pm.sh \ @@ -XXX,XX +XXX,XX @@ TEST_GEN_FILES := \ mptcp_inq \ mptcp_sockopt \ pm_nl_ctl \ + tls \ # end of TEST_GEN_FILES TEST_FILES := \ diff --git a/tools/testing/selftests/net/mptcp/config b/tools/testing/selftests/net/mptcp/config index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/mptcp/config +++ b/tools/testing/selftests/net/mptcp/config @@ -XXX,XX +XXX,XX @@ CONFIG_NFT_SOCKET=m CONFIG_NFT_TPROXY=m CONFIG_SYN_COOKIES=y CONFIG_VETH=y +CONFIG_TLS=m +CONFIG_CRYPTO_ARIA=m +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_CHACHA20POLY1305=m +CONFIG_CRYPTO_SM4_GENERIC=m diff --git a/tools/testing/selftests/net/mptcp/mptcp_tls.sh b/tools/testing/selftests/net/mptcp/mptcp_tls.sh new file mode 100755 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/testing/selftests/net/mptcp/mptcp_tls.sh @@ -XXX,XX +XXX,XX @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(dirname "${0}")/mptcp_lib.sh" + +ret=0 +ns1="" + +# This function is used in the cleanup trap +#shellcheck disable=SC2317,SC2329 +cleanup() +{ + if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then + kill "$pid" 2>/dev/null + wait "$pid" 2>/dev/null + fi + + mptcp_lib_ns_exit "$ns1" +} + +init() +{ + local max="${1:-4}" + + mptcp_lib_ns_init ns1 + + mptcp_lib_pm_nl_set_limits "$ns1" "$max" "$max" + + local i + for i in $(seq 1 "$max"); do + mptcp_lib_pm_nl_add_endpoint "$ns1" \ + "127.0.0.1" flags signal port 1000"$i" + done +} + +trap cleanup EXIT + +mptcp_lib_check_mptcp +# Temporarily set max to '0' to disable multipath testing, +# as it depends on "mptcp: fix stall because of data_ready" series of fixes. +# It will be re-enabled together with that series later as a squash-to patch. +init 0 + +ip netns exec "$ns1" ./tls -v 12_aes_gcm_mptcp \ + -v 13_aes_gcm_mptcp \ + -v 12_chacha_mptcp \ + -v 13_chacha_mptcp \ + -v 13_sm4_gcm_mptcp \ + -v 13_sm4_ccm_mptcp \ + -v 12_aes_ccm_mptcp \ + -v 13_aes_ccm_mptcp \ + -v 12_aes_gcm_256_mptcp \ + -v 13_aes_gcm_256_mptcp \ + -v 13_nopad_mptcp \ + -v 12_aria_gcm_mptcp \ + -v 12_aria_gcm_256_mptcp & +pid=$! +wait $pid +ret=$? + +mptcp_lib_result_print_all_tap +exit $ret diff --git a/tools/testing/selftests/net/mptcp/tls.c b/tools/testing/selftests/net/mptcp/tls.c new file mode 120000 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/testing/selftests/net/mptcp/tls.c @@ -0,0 +1 @@ +../tls.c \ No newline at end of file -- 2.51.0
From: Geliang Tang <tanggeliang@kylinos.cn> v25: - patch 1: add sendmsg_locked to MPTCP proto_ops (split mptcp_sendmsg into locked and wrapper). - patch 2: make TLS use sk->sk_socket->ops->sendmsg_locked instead of tcp_sendmsg_locked directly. - patch 3: implement peek_len for MPTCP (reuse mptcp_inq) and assign to proto_ops. - patch 4: replace all tcp_inq() calls in TLS with sk->sk_socket->ops->peek_len. - patch 5: store original socket poll method in tls_context->sk_poll and use it in tls_sk_poll instead of hard-coded tcp_poll. - patch 6: store original read_sock method in tls_context->sk_read_sock and use it in tls_strp_read_copyin instead of tcp_read_sock. - patch 7 (was v24 patch 3): per-protocol cache for MPTCP support, but all tls_toe related modifications have been removed (only kept changes that ensure compilation passes). - patch 8 (was v24 patch 4): introduce tls_prot_ops structure, simplified to only include recv_skb, lock_is_held, read_done, get_skb_seq, skb_get_header, epollin_ready, check_app_limited. - patch 9 (was v24 patch 5): store protocol ops pointer in tls_prot and use indirect calls, adapted to use skb_get_header instead of skb_copy_bits. - patch 10 (was v24 patch 6): implement MPTCP-specific tls_prot_ops, with mptcp_skb_get_header (replaces skb_copy_bits variant). Remove mptcp_inq and mptcp_sendmsg_locked from this patch (already added earlier). - patch 12: drop the socket lock acquisition before calling sk_is_readable(). v24: - patch 1 (new): - Add standalone fix: restore sk_prot before calling original destructor in tls_toe_sk_destruct() to prevent use-after-free. - patch 2 (new): - Add standalone fix: use READ_ONCE() and NULL check in tls_get_ctx() for lockless readers (e.g., tls_sk_poll), removing the need for smp_rmb() barriers. - patch 3: - Remove smp_store_release() and smp_rmb() barriers from TLS data path. Rely on READ_ONCE() in tls_get_ctx() and plain WRITE_ONCE() in update_sk_prot() instead. - patch 5: - Add new helper tls_prot_poll() for fallback handling when tls_get_ctx() returns NULL (e.g., during socket teardown). - Replace ops->skb_copy_bits in more places: tls_strp_copyin_frag(), tls_strp_skb_copy(), and other strparser helpers. - patch 8: - Hold socket lock in mptcp_stream_is_readable() before calling sk_is_readable() to prevent race conditions. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1780621326.git.tanggeliang@kylinos.cn/ v23: - patch 1: - Double-check using tls_prot_find() to avoid unnecessary allocation and lock contention. - patch 5: - Rewrite mptcp_skb_copy_bits() - patch 7: - Implement mptcp_getsockopt_tcp_ulp() directly, eliminating the call to tcp_sock_get_ulp() and thereby avoiding the double-fetch vulnerability. - patch 8: - Simplify mptcp_setsockopt_tcp_ulp() by removing redundant fallback checks. Setting "tls" on a fallback MPTCP socket now naturally fails with -EEXIST because the ULP is already "mptcp". - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1780362942.git.tanggeliang@kylinos.cn/ v22: - patches 1-4 (new): - Add standalone fixes for TLS/TCP ULP issues, according to Sashiko comments on the previous version, and placed at the beginning of the series. - patch 5 (merge of v21 01+02+05): - Add sk->sk_socket NULL check in tls_build_proto() - Update update_sk_prot() to use smp_store_release() for both sk->sk_prot and sk->sk_socket->ops - patch 6 (was v21 03): - "tls: introduce tls protocol ops structure" - Add skb_copy_bits callback to struct tls_prot_ops, and initialize it in tls_tcp_ops as skb_copy_bits - patch 9: - Add mptcp_skb_copy_bits(), implemented by Gang Yan, to handle fragmented MPTCP skbs when copying TLS record headers - patch 20: - Enable multipath testing. - Depends on: mptcp: address stall under memory pressure, v10 - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1780052851.git.tanggeliang@kylinos.cn/ v21: - patch 1: - Rename struct tls_proto to struct tls_prot (including all related functions and variables) for clarity - Add missing rcu_barrier() in tls_prot_cleanup() to ensure all RCU callbacks complete before module unload - Fix module reference leak by adding module_put(prot->ops->owner) in the cleanup loop of tls_prot_cleanup() - patch 2 (new): - split from patch 1. - patch 5 (new): - Add memory barriers in tls_sk_poll() and tls_sw_sock_is_readable() to pair with smp_store_release() in update_sk_prot() - Replace direct tcp_poll() call with indirect call via tls_ctx->prot->ops->poll for proper MPTCP support - patch 11: - Expand kernel config: add CONFIG_INET_ESP, CONFIG_INET_ESPINTCP, CONFIG_INET6_ESP, CONFIG_INET6_ESPINTCP to support espintcp ULP testing - patch 12: - In ulp_sock_pair(), accept EOPNOTSUPP (in addition to ENOENT) when setting TCP_ULP fails, as MPTCP sockets may return this error - patch 16 (new): - Add TEST_F_TIMEOUT(tls, multi_chunk_sendfile, 240) to prevent timeout failures on MPTCP configurations - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1779959644.git.tanggeliang@kylinos.cn/ v20: - patch 1: - Use kfree_rcu() instead of synchronous kfree() in tls_proto_cleanup() and tls_proto_put() to prevent use-after-free for RCU readers - Add duplicate check under tls_proto_lock before inserting new tls_proto to list to prevent race condition - Fix reference counting: drop the initial reference from tls_build_proto() after successful tls_ctx_create() to prevent refcount leak - patch 2: - Replace spin_lock() with spin_lock_bh() in tls_register_prot_ops() and tls_unregister_prot_ops() to avoid Lockdep splat (softirq context usage) - patch 3: - Add memory barrier ordering in tls_sk_poll() to prevent NULL pointer dereference during concurrent setsockopt(TCP_ULP) - Move try_module_get() inside tls_prot_ops_find() while holding the lock to prevent ops structure from being freed before module reference is acquired - patch 8: - Add missing fallback check __mptcp_check_fallback(msk) before calling mptcp_setsockopt_tcp_ulp() to prevent TLS being attached to fallback sockets - Re-check fallback status inside mptcp_setsockopt_tcp_ulp() after acquiring socket lock to eliminate TOCTOU race - patch 10: - Remove unused _metadata parameter from is_mptcp_enable() - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1779788090.git.tanggeliang@kylinos.cn/ v19: - Remove RCU from tls_proto and tls_prot_ops management Replace RCU with spinlock (tls_proto_lock) for all list operations. Remove rcu_head from struct tls_proto, eliminate call_rcu() and synchronize_rcu() calls. Use list_del + kfree directly in tls_proto_cleanup() and tls_proto_put(). - Add memory barrier in update_sk_prot() Use smp_store_release() when setting sk->sk_socket->ops to ensure it is not visible before icsk_ulp_data. Add explanatory comment to prevent NULL pointer dereference in concurrent tls_sk_poll() due to CPU reordering. - Add module owner field to tls_prot_ops Add .owner = THIS_MODULE to tls_tcp_ops (and tls_mptcp_ops in MPTCP side). Add try_module_get(ops->owner) in tls_build_proto() before caching ops pointer. Add module_put(proto->ops->owner) in tls_proto_put() when releasing proto. - Fix tls_toe_sk_destruct use-after-free Restore sk->sk_prot before calling original destructor to prevent UAF when __sk_destruct() accesses sk->sk_prot->destroy. - Optimize indirect call performance Delay inq and get_skb_seq indirect calls in tls_read_flush_backlog() and tls_rx_msg_size() to avoid unnecessary retpoline overhead on fast path. - Fix shutdown_reuse test flakiness Replace MPTCP-specific wait with generic bind retry loop. Retry bind() on EINVAL up to 1000 times (1 second) to handle asynchronous state transitions for both TCP and MPTCP. - Remove redundant tls_ctx->proto->ops NULL checks Rely on memory barrier to guarantee ordering, eliminate unnecessary NULL checks that could introduce other issues. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1779355169.git.tanggeliang@kylinos.cn/ v18: - add ip_ver field to tls_proto and pass it to tls_proto_find to distinguish IPv4/IPv6 instances - convert tls_proto_mutex to spinlock, and convert tls_proto_cleanup to use call_rcu and rcu_barrier for softirq context compatibility - add tls_proto_put() for atomic refcount decrement + list_del + call_rcu, and simplify tls_ctx_free and tls_init error paths to use it - use GFP_ATOMIC for tls_proto allocation in tls_build_proto - reorder tls_register cleanup labels to unwind correctly on error - implement new mptcp_inq - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1777459066.git.tanggeliang@kylinos.cn/ v17: - remove owner from tls_prot_ops since both TCP and MPTCP are built-in and cannot be unloaded - add rcu_head to tls_proto for delayed freeing - replace synchronize_rcu with call_rcu in tls_ctx_free - remove module refcounting (try_module_get / module_put) from tls_build_proto and tls_init - simplify tls_proto_cleanup to directly free all protos without refcnt check - change tls_proto refcnt from 2 to 1 (only socket reference, no list reference) - move synchronize_rcu outside spinlock in tls_unregister_prot_ops - use kzalloc_obj instead of kzalloc to fix the checkpatch warning - update commit logs - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1777026753.git.tanggeliang@kylinos.cn/ v16: - drop rcu_head from struct tls_proto, use refcnt for lifecycle management. - add back TLS_NUM_PROTS to handle IPv4/IPv6 separately. - add .owner field to tls_tcp_ops and tls_mptcp_ops (THIS_MODULE). - add module refcounting (try_module_get / module_put) in tls_build_proto and tls_init. - add missing NULL check for tls_ctx->proto->ops in tls_sk_poll. - add RCU read lock protection in tls_register_prot_ops. - add error handling for tls_register_prot_ops calls in tls_register (with rollback on failure). - adjust MPTCP cleanup: move tcp_cleanup_ulp from mptcp_destroy_common to mptcp_destroy. - remove increase_rlimit from selftest and fix fd check. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1776924681.git.tanggeliang@kylinos.cn/ v15: - patch 1: add proto parameter for tls_toe_bypass. - patch 1: add a proto null-check in update_sk_prot. - patch 1: hold mutex_lock in tls_proto_cleanup. - patch 14: raise the limit of file descriptor values to 4096 to avoid test failures. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1776469068.git.tanggeliang@kylinos.cn/ v14: - address review comments from sashiko - patch 1: add rcu for tls_proto, add tls_proto_cleanup. - patch 2: add unregister helper. - patch 3: add tls_prot_ops pointer to tls_proto, instead of tls_context - patch 5: update mptcp_get_skb_seq, using map_seq - offset, then the patch "tls: add skb offset check for mptcp" can be dropped. - patch 7: check len < 0. - patch 8: call tcp_cleanup_ulp in mptcp_destroy_common. - patch 9: replace all "tls" as "espintcp" in sock_test_tcpulp. - patch 10: add is_mptcp_enable helper. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1775476921.git.tanggeliang@kylinos.cn/ v13: - patch 1: Add new patch "add per-protocol cache" to address AI review. - patch 2: Hold RCU read lock in tls_prot_ops_find(). - patch 3: Set icsk_ulp_data to NULL in error path. - patch 6: Use spin_is_locked() instead of lockdep_is_held() to fix build errors. - patch 9: Drop tcp_sock_set_ulp(). - patch 11: Remove the "return" statement in ulp_sock_pair and check the return values of socket(). - patch 14: Update wait_for_tcp_close(). - patch 16: Add a max argument to init() and set it to '0' to disable multipath testing, so that this series does not depend on the "mptcp: fix stall because of data_ready" series. Multipath testing will be re-enabled together with that series later, as a squash-to patch. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1775227717.git.tanggeliang@kylinos.cn/ v12: - Thanks for the help from Paolo and Gang Yan, I finally solved the deadlock issue in read_sock. As a result, the patch "mptcp: avoid sleeping in read_sock path under softirq" in v11 has been dropped, and instead a lock_is_held interface has been added to struct tls_prot_ops. When MPTCP implements this interface, it not only checks sock_owned_by_user_nocheck(sk) as TCP does, but also needs to check whether the MPTCP data lock is held. - Update selftests to make them more stable. - Fix shellcheck errors for the selftests. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1775115102.git.tanggeliang@kylinos.cn/ v11: - Fix memory leak errors reported by CI. In v10, these occurred in the shutdown_reuse test and "usleep(500000)" caused the memory leaks. In v11, a dedicated helper wait_for_tcp_close() has been added to provide an appropriate delay. - Drop the code that used mptcp_data_trylock() in mptcp_move_skbs() to fix a deadlock issue, as that deadlock no longer occurs in v11. - Do not add "mptcp" variable for the "tls_err" tests, adding it for the "tls" tests is sufficient. - No longer increase timeout values for poll/epoll tests, as they are no longer needed. - Add ns1 definition in mptcp_tls.sh to fix "ns1 is referenced but not assigned" error. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1773911536.git.tanggeliang@kylinos.cn/ v10: - Address comments by ai review: - patch 2: call tls_ctx_free(sk, ctx) and clear icsk_ulp_data before goto out. - patch 3: update commit log as "validate each SKB's offset except the first". - patch 5: add sock_owned_by_user() checks. - patch 7: disable device offload for MPTCP sockets. - patch 9: use TCP_ULP_NAME_MAX in mptcp_setsockopt_tcp_ulp(), drop SOL_TLS in mptcp_supported_sockopt(). - Make .get_skb_off optional instead of mandatory, TCP does not need to define it. - Test "espintcp" ULP instead of "smc" in patch 10. "smc" ULP is removed recently. - With Gang Yan's "mptcp: fix stall because of data_ready" v3, mptcp tls selftests can run without failures. Now add them in this set. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1773737371.git.tanggeliang@kylinos.cn/ v9: - add a new patch to "add MPTCP SKB offset check in strp queue walk", thanks to Gang Yan for the fix. - add a new patch to "avoid deadlocks in read_sock path", replacing the "in_softirq()" check used in v8. - update the selftests. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1773365606.git.tanggeliang@kylinos.cn/ v8: - do not hold tls_prot_ops_lock in tls_init(); otherwise, a deadlock occurs. - change return value of mptcp_stream_is_readable() as 'bool' to fix the "expected restricted __poll_t" warning reported by CI. - fixed other CI checkpatch warnings regarding excessively long lines. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1768294706.git.tanggeliang@kylinos.cn/ v7: - Passing an MPTCP socket to tcp_sock_rate_check_app_limited() causes a crash. In v7, an MPTCP version of check_app_limited() is implemented, which calls tcp_sock_rate_check_app_limited() for each subflow. - Register tls_tcp_ops and tls_mptcp_ops in tls_register() rather than in tls_init(). - Set ctx->ops in tls_init() instead of in do_tls_setsockopt_conf(). - Keep tls_device.c unchanged. MPTCP TLS_HW mode has not been implemented yet, so EOPNOTSUPP is returned in this case. - Also add TCP TLS tests in mptcp_join.sh. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1768284047.git.tanggeliang@kylinos.cn/ v6: - register each ops as Matt suggested. - drop sk_is_msk(). - add tcp_sock_get_ulp/tcp_sock_set_ulp helpers. - set another ULP in sock_test_tcpulp as Matt suggested. - add tls tests using multiple subflows in mptcp_join.sh. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1767518836.git.tanggeliang@kylinos.cn/ v5: - As suggested by Mat and Matt, this set introduces struct tls_prot_ops for TLS. - Includes Gang Yan's patches to add MPTCP support to the TLS selftests. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1766372799.git.tanggeliang@kylinos.cn/ v4: - split "tls: add MPTCP protocol support" into smaller, more focused patches. - a new mptcp_inq helper has been implemented instead of directly using mptcp_inq_hint to fix the issue mentioned in [1]. - add sk_is_msk helper. - the 'expect' parameter will no longer be added to sock_test_tcpulp. Instead, SOCK_TEST_TCPULP items causing the tests failure will be directly removed. - remove the "TCP KTLS" tests, keeping only the MPTCP-related ones. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1765505775.git.tanggeliang@kylinos.cn/ [1] https://patchwork.kernel.org/project/mptcp/patch/ce74452f4c095a1761ef493b767b4bd9f9c14359.1764333805.git.tanggeliang@kylinos.cn/ v3: - mptcp_read_sock() and mptcp_poll() are not exported, as mptcp_sockopt test does not use read_sock/poll interfaces. They will be exported when new tests are added in the future. - call mptcp_inq_hint in tls_device_rx_resync_new_rec(), tls_device_core_ctrl_rx_resync() and tls_read_flush_backlog() too. - update selftests. - Link: https://patchwork.kernel.org/project/mptcp/cover/cover.1763800601.git.tanggeliang@kylinos.cn/ v2: - fix disconnect. - update selftests. This series adds KTLS support for MPTCP. Since the ULP of msk is not being used, ULP KTLS can be directly configured onto msk without affecting its communication. Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/480 Gang Yan (1): mptcp: update mptcp_check_readable helper Geliang Tang (21): mptcp: add sendmsg_locked to proto_ops tls: use sendmsg_locked from the underlying socket mptcp: implement peek_len for proto_ops tls: replace tcp_inq with socket peek_len tls: store original poll for non-TCP sockets tls: store original read_sock for non-TCP sockets tls: add per-protocol cache for mptcp support tls: introduce tls protocol ops structure tls: store protocol ops pointer in tls_proto mptcp: implement mptcp-specific tls protocol ops tls: disable device offload for mptcp sockets mptcp: implement ulp getsockopt for tls support mptcp: implement ulp setsockopt for tls support selftests: mptcp: connect: use espintcp for ulp test selftests: tls: add mptcp variant for testing selftests: tls: increase pollin timeouts for mptcp selftests: tls: increase nonblocking data size for mptcp selftests: tls: retry bind for mptcp in shutdown_reuse selftests: tls: set timeout for multi_chunk_sendfile selftests: tls: add mptcp test cases selftests: mptcp: cover mptcp tls tests include/net/mptcp.h | 2 + include/net/tcp.h | 1 + include/net/tls.h | 32 ++ include/net/tls_toe.h | 2 +- net/ipv4/tcp.c | 9 +- net/mptcp/protocol.c | 175 ++++++++++- net/mptcp/protocol.h | 1 + net/mptcp/sockopt.c | 68 ++++- net/tls/tls.h | 2 +- net/tls/tls_device.c | 10 +- net/tls/tls_main.c | 274 +++++++++++++++--- net/tls/tls_strp.c | 35 ++- net/tls/tls_sw.c | 9 +- net/tls/tls_toe.c | 4 +- tools/testing/selftests/net/mptcp/.gitignore | 1 + tools/testing/selftests/net/mptcp/Makefile | 2 + tools/testing/selftests/net/mptcp/config | 9 + .../selftests/net/mptcp/mptcp_connect.c | 4 +- .../testing/selftests/net/mptcp/mptcp_tls.sh | 61 ++++ tools/testing/selftests/net/mptcp/tls.c | 1 + tools/testing/selftests/net/tls.c | 159 +++++++++- 21 files changed, 779 insertions(+), 82 deletions(-) create mode 100755 tools/testing/selftests/net/mptcp/mptcp_tls.sh create mode 120000 tools/testing/selftests/net/mptcp/tls.c -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> MPTCP currently provides a standard sendmsg() implementation which acquires and releases the socket lock internally. However, certain upper layers (e.g., TLS) need to call the sendmsg method while the socket lock is already held. Split the existing mptcp_sendmsg() into mptcp_sendmsg_locked() which assumes the caller holds the socket lock, and a tiny wrapper mptcp_sendmsg() that acquires the lock and calls the locked version. Expose .sendmsg_locked in both mptcp_stream_ops and mptcp_v6_stream_ops. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- net/mptcp/protocol.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -XXX,XX +XXX,XX @@ static void mptcp_rps_record_subflows(const struct mptcp_sock *msk) } } -static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) +static int mptcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t len) { struct mptcp_sock *msk = mptcp_sk(sk); struct page_frag *pfrag; @@ -XXX,XX +XXX,XX @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) msg->msg_flags &= MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_FASTOPEN | MSG_EOR; - lock_sock(sk); - mptcp_rps_record_subflows(msk); if (unlikely(inet_test_bit(DEFER_CONNECT, sk) || @@ -XXX,XX +XXX,XX @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) } out: - release_sock(sk); return copied; do_error: @@ -XXX,XX +XXX,XX @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) goto out; } +static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) +{ + int ret; + + lock_sock(sk); + ret = mptcp_sendmsg_locked(sk, msg, len); + release_sock(sk); + + return ret; +} + static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied); static void mptcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb) @@ -XXX,XX +XXX,XX @@ static const struct proto_ops mptcp_stream_ops = { .set_rcvlowat = mptcp_set_rcvlowat, .read_sock = mptcp_read_sock, .splice_read = mptcp_splice_read, + .sendmsg_locked = mptcp_sendmsg_locked, }; static struct inet_protosw mptcp_protosw = { @@ -XXX,XX +XXX,XX @@ static const struct proto_ops mptcp_v6_stream_ops = { .set_rcvlowat = mptcp_set_rcvlowat, .read_sock = mptcp_read_sock, .splice_read = mptcp_splice_read, + .sendmsg_locked = mptcp_sendmsg_locked, }; static struct proto mptcp_v6_prot; -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> TLS offload (device and sw) may call tcp_sendmsg_locked() directly when pushing TLS records. This assumes the underlying socket is always a TCP socket. With MPTCP, the socket can be an MPTCP socket, which does not directly expose a sendmsg_locked method via its proto_ops. Replace the hard-coded tcp_sendmsg_locked() call with sk->sk_socket->ops->sendmsg_locked(). This enables TLS to work transparently over any socket that implements .sendmsg_locked, including MPTCP after the previous commit. The change is safe because both TCP and MPTCP now provide a conformant .sendmsg_locked implementation. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- net/tls/tls_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -XXX,XX +XXX,XX @@ int tls_push_sg(struct sock *sk, bvec_set_page(&bvec, p, size, offset); iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - ret = tcp_sendmsg_locked(sk, &msg, size); + ret = sk->sk_socket->ops->sendmsg_locked(sk, &msg, size); if (ret != size) { if (ret > 0) { -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> The TLS stack uses tcp_inq() to query the amount of data available in the receive queue without consuming it. For MPTCP sockets, this information is not directly available from a TCP subflow; it must be computed from the MPTCP receive queue and the current mapping. Introduce mptcp_peek_len() which returns the number of bytes that can be peeked from the MPTCP socket. It reuses the existing mptcp_inq() helper (used by ioctl SIOCINQ). The implementation considers the first skb in the receive queue, the current ack_seq, and handles the FIN case. Assign .peek_len in both mptcp_stream_ops and mptcp_v6_stream_ops so that upper layers (e.g., TLS) can obtain the correct in-queue byte count for an MPTCP connection. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- net/mptcp/protocol.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -XXX,XX +XXX,XX @@ static ssize_t mptcp_splice_read(struct socket *sock, loff_t *ppos, return ret; } +static int mptcp_inq(struct sock *sk) +{ + const struct mptcp_sock *msk = mptcp_sk(sk); + const struct sk_buff *skb; + + if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) + return 0; + + skb = skb_peek(&sk->sk_receive_queue); + if (skb) { + u64 answ = READ_ONCE(msk->ack_seq) - MPTCP_SKB_CB(skb)->map_seq; + + if (answ >= INT_MAX) + answ = INT_MAX; + + /* Subtract 1, if FIN was received */ + if (answ && + (sk->sk_state == TCP_CLOSE || + (sk->sk_shutdown & RCV_SHUTDOWN))) + answ--; + + return (int)answ; + } + + return 0; +} + +static int mptcp_peek_len(struct socket *sock) +{ + return mptcp_inq(sock->sk); +} + static const struct proto_ops mptcp_stream_ops = { .family = PF_INET, .owner = THIS_MODULE, @@ -XXX,XX +XXX,XX @@ static const struct proto_ops mptcp_stream_ops = { .read_sock = mptcp_read_sock, .splice_read = mptcp_splice_read, .sendmsg_locked = mptcp_sendmsg_locked, + .peek_len = mptcp_peek_len, }; static struct inet_protosw mptcp_protosw = { @@ -XXX,XX +XXX,XX @@ static const struct proto_ops mptcp_v6_stream_ops = { .read_sock = mptcp_read_sock, .splice_read = mptcp_splice_read, .sendmsg_locked = mptcp_sendmsg_locked, + .peek_len = mptcp_peek_len, }; static struct proto mptcp_v6_prot; -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> TLS (device, strparser, and software) calls tcp_inq() directly to determine how much data is still pending in the socket receive queue. This breaks when the underlying socket is not TCP (e.g., MPTCP). Switch all occurrences of tcp_inq(sk) to sk->sk_socket->ops-> peek_len(sk->sk_socket). This operation is implemented for both TCP and MPTCP (after the previous commits), making TLS transparently usable over MPTCP connections. The change is straightforward: every place where TLS needed the available in-queue bytes now uses the protocol-specific peek_len method instead of assuming a TCP socket. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- net/tls/tls_device.c | 4 ++-- net/tls/tls_strp.c | 6 ++++-- net/tls/tls_sw.c | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -XXX,XX +XXX,XX @@ void tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq) /* head of next rec is already in, note that the sock_inq will * include the currently parsed message when called from parser */ - sock_data = tcp_inq(sk); + sock_data = sk->sk_socket->ops->peek_len(sk->sk_socket); if (sock_data > rcd_len) { trace_tls_device_rx_resync_nh_delay(sk, sock_data, rcd_len); @@ -XXX,XX +XXX,XX @@ static void tls_device_core_ctrl_rx_resync(struct tls_context *tls_ctx, rxm = strp_msg(skb); /* head of next rec is already in, parser will sync for us */ - if (tcp_inq(sk) > rxm->full_len) { + if (sk->sk_socket->ops->peek_len(sk->sk_socket) > rxm->full_len) { trace_tls_device_rx_resync_nh_schedule(sk); ctx->resync_nh_do_now = 1; } else { diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_strp.c +++ b/net/tls/tls_strp.c @@ -XXX,XX +XXX,XX @@ bool tls_strp_msg_load(struct tls_strparser *strp, bool force_refresh) { struct strp_msg *rxm; struct tls_msg *tlm; + int inq; DEBUG_NET_WARN_ON_ONCE(!strp->msg_ready); DEBUG_NET_WARN_ON_ONCE(!strp->stm.full_len); if (!strp->copy_mode && force_refresh) { - if (unlikely(tcp_inq(strp->sk) < strp->stm.full_len)) { + inq = strp->sk->sk_socket->ops->peek_len(strp->sk->sk_socket); + if (unlikely(inq < strp->stm.full_len)) { WRITE_ONCE(strp->msg_ready, 0); memset(&strp->stm, 0, sizeof(strp->stm)); return false; @@ -XXX,XX +XXX,XX @@ static int tls_strp_read_sock(struct tls_strparser *strp) { int sz, inq; - inq = tcp_inq(strp->sk); + inq = strp->sk->sk_socket->ops->peek_len(strp->sk->sk_socket); if (inq < 1) return 0; diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -XXX,XX +XXX,XX @@ tls_read_flush_backlog(struct sock *sk, struct tls_prot_info *prot, size_t *flushed_at) { size_t max_rec; + int inq; if (len_left <= decrypted) return false; + inq = sk->sk_socket->ops->peek_len(sk->sk_socket); max_rec = prot->overhead_size - prot->tail_size + TLS_MAX_PAYLOAD_SIZE; - if (done - *flushed_at < SZ_128K && tcp_inq(sk) > max_rec) + if (done - *flushed_at < SZ_128K && inq > max_rec) return false; *flushed_at = done; -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> The TLS layer currently calls tcp_poll() directly from its own poll handler (tls_sk_poll). This breaks when the underlying socket is not TCP, for example when TLS is used over MPTCP. Store the original socket's poll method (sk->sk_socket->ops->poll) in a new .sk_poll callback inside struct tls_context during TLS initialization. Then modify tls_sk_poll() to invoke this stored callback instead of hard-coded tcp_poll(). This allows TLS to correctly poll on any socket type that implements the standard poll interface, including MPTCP. No functional change for plain TCP sockets because they already use tcp_poll (which is the same as the stored method). Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- include/net/tls.h | 2 ++ net/tls/tls_main.c | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -XXX,XX +XXX,XX @@ struct tls_context { struct sock *sk; void (*sk_destruct)(struct sock *sk); + __poll_t (*sk_poll)(struct file *file, struct socket *sock, + struct poll_table_struct *wait); union tls_crypto_context crypto_send; union tls_crypto_context crypto_recv; diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -XXX,XX +XXX,XX @@ static __poll_t tls_sk_poll(struct file *file, struct socket *sock, u8 shutdown; int state; - mask = tcp_poll(file, sock, wait); + tls_ctx = tls_get_ctx(sk); + if (!tls_ctx) + return EPOLLHUP | EPOLLERR; + + mask = tls_ctx->sk_poll(file, sock, wait); state = inet_sk_state_load(sk); shutdown = READ_ONCE(sk->sk_shutdown); if (unlikely(state != TCP_ESTABLISHED || shutdown & RCV_SHUTDOWN)) return mask; - tls_ctx = tls_get_ctx(sk); ctx = tls_sw_ctx_rx(tls_ctx); psock = sk_psock_get(sk); @@ -XXX,XX +XXX,XX @@ static int tls_init(struct sock *sk) ctx->tx_conf = TLS_BASE; ctx->rx_conf = TLS_BASE; ctx->tx_max_payload_len = TLS_MAX_PAYLOAD_SIZE; + ctx->sk_poll = sk->sk_socket->ops->poll; update_sk_prot(sk, ctx); out: write_unlock_bh(&sk->sk_callback_lock); -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> TLS strparser uses tcp_read_sock() to copy data from the underlying socket. This assumes the socket is always TCP, which fails when TLS is used over MPTCP. Store the original socket's read_sock method (sk->sk_socket->ops-> read_sock) in a new .sk_read_sock callback inside struct tls_context. Then in tls_strp_read_copyin(), call this stored callback instead of the hard-coded tcp_read_sock(). With this change, TLS strparser works transparently over any socket that implements .read_sock (including MPTCP, which already provides mptcp_read_sock). Behavior for plain TCP remains unchanged. Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- include/net/tls.h | 2 ++ net/tls/tls_main.c | 1 + net/tls/tls_strp.c | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/net/tls.h b/include/net/tls.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -XXX,XX +XXX,XX @@ struct tls_context { void (*sk_destruct)(struct sock *sk); __poll_t (*sk_poll)(struct file *file, struct socket *sock, struct poll_table_struct *wait); + int (*sk_read_sock)(struct sock *sk, read_descriptor_t *desc, + sk_read_actor_t recv_actor); union tls_crypto_context crypto_send; union tls_crypto_context crypto_recv; diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -XXX,XX +XXX,XX @@ static int tls_init(struct sock *sk) ctx->rx_conf = TLS_BASE; ctx->tx_max_payload_len = TLS_MAX_PAYLOAD_SIZE; ctx->sk_poll = sk->sk_socket->ops->poll; + ctx->sk_read_sock = sk->sk_socket->ops->read_sock; update_sk_prot(sk, ctx); out: write_unlock_bh(&sk->sk_callback_lock); diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_strp.c +++ b/net/tls/tls_strp.c @@ -XXX,XX +XXX,XX @@ static int tls_strp_copyin(read_descriptor_t *desc, struct sk_buff *in_skb, static int tls_strp_read_copyin(struct tls_strparser *strp) { + struct tls_context *ctx = tls_get_ctx(strp->sk); read_descriptor_t desc; desc.arg.data = strp; @@ -XXX,XX +XXX,XX @@ static int tls_strp_read_copyin(struct tls_strparser *strp) desc.count = 1; /* give more than one skb per call */ /* sk should be locked here, so okay to do read_sock */ - tcp_read_sock(strp->sk, &desc, tls_strp_copyin); + ctx->sk_read_sock(strp->sk, &desc, tls_strp_copyin); return desc.error; } -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> The TLS ULP uses global static arrays to cache base protocol operations. When MPTCP sockets enable TLS, they overwrite these global caches when building for MPTCP, causing active TCP TLS sockets to use MPTCP-specific ops. This leads to type confusion and kernel panics. Fix by replacing the global caches with a per-protocol linked list. Each protocol (TCP, MPTCP, etc.) now has its own cached operations, stored in struct tls_prot and referenced from tls_context. Add a struct tls_prot *prot parameter to tls_ctx_create() and tls_toe_bypass(), and store the pointer in tls_context. This allows protocol-specific TLS operation tables (e.g., for MPTCP) to be passed down. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- include/net/tls.h | 12 ++++ include/net/tls_toe.h | 2 +- net/tls/tls.h | 2 +- net/tls/tls_main.c | 139 +++++++++++++++++++++++++++++++----------- net/tls/tls_toe.c | 4 +- 5 files changed, 118 insertions(+), 41 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -XXX,XX +XXX,XX @@ struct tls_prot_info { u16 tail_size; }; +struct tls_prot { + struct rcu_head rcu; + refcount_t refcnt; + struct list_head list; + int ip_ver; + const struct proto *prot; + struct proto prots[TLS_NUM_CONFIG][TLS_NUM_CONFIG]; + struct proto_ops proto_ops[TLS_NUM_CONFIG][TLS_NUM_CONFIG]; +}; + struct tls_context { /* read-only cache line */ struct tls_prot_info prot_info; @@ -XXX,XX +XXX,XX @@ struct tls_context { struct proto *sk_proto; struct sock *sk; + struct tls_prot *prot; + void (*sk_destruct)(struct sock *sk); __poll_t (*sk_poll)(struct file *file, struct socket *sock, struct poll_table_struct *wait); diff --git a/include/net/tls_toe.h b/include/net/tls_toe.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/tls_toe.h +++ b/include/net/tls_toe.h @@ -XXX,XX +XXX,XX @@ struct tls_toe_device { struct kref kref; }; -int tls_toe_bypass(struct sock *sk); +int tls_toe_bypass(struct sock *sk, struct tls_prot *prot); int tls_toe_hash(struct sock *sk); void tls_toe_unhash(struct sock *sk); diff --git a/net/tls/tls.h b/net/tls/tls.h index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls.h +++ b/net/tls/tls.h @@ -XXX,XX +XXX,XX @@ struct tls_rec { int __net_init tls_proc_init(struct net *net); void __net_exit tls_proc_fini(struct net *net); -struct tls_context *tls_ctx_create(struct sock *sk); +struct tls_context *tls_ctx_create(struct sock *sk, struct tls_prot *prot); void tls_ctx_free(struct sock *sk, struct tls_context *ctx); void update_sk_prot(struct sock *sk, struct tls_context *ctx); diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -XXX,XX +XXX,XX @@ CHECK_CIPHER_DESC(TLS_CIPHER_SM4_CCM, tls12_crypto_info_sm4_ccm); CHECK_CIPHER_DESC(TLS_CIPHER_ARIA_GCM_128, tls12_crypto_info_aria_gcm_128); CHECK_CIPHER_DESC(TLS_CIPHER_ARIA_GCM_256, tls12_crypto_info_aria_gcm_256); -static const struct proto *saved_tcpv6_prot; -static DEFINE_MUTEX(tcpv6_prot_mutex); -static const struct proto *saved_tcpv4_prot; -static DEFINE_MUTEX(tcpv4_prot_mutex); -static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG]; -static struct proto_ops tls_proto_ops[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG]; +static LIST_HEAD(tls_prot_list); +static DEFINE_SPINLOCK(tls_prot_lock); static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], const struct proto *base); +static struct tls_prot *tls_prot_find(const struct proto *proto, + int ip_ver) +{ + struct tls_prot *prot, *ret = NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(prot, &tls_prot_list, list) { + if (prot->prot == proto && prot->ip_ver == ip_ver && + refcount_inc_not_zero(&prot->refcnt)) { + ret = prot; + break; + } + } + rcu_read_unlock(); + return ret; +} + +static void tls_prot_free(struct rcu_head *rcu) +{ + struct tls_prot *prot = container_of(rcu, struct tls_prot, rcu); + + kfree(prot); +} + +static void tls_prot_cleanup(void) +{ + struct tls_prot *prot, *tmp; + + spin_lock_bh(&tls_prot_lock); + list_for_each_entry_safe(prot, tmp, &tls_prot_list, list) { + list_del_rcu(&prot->list); + call_rcu(&prot->rcu, tls_prot_free); + } + spin_unlock_bh(&tls_prot_lock); + rcu_barrier(); +} + void update_sk_prot(struct sock *sk, struct tls_context *ctx) { - int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4; + struct tls_prot *prot = ctx->prot; + + if (!prot) + return; WRITE_ONCE(sk->sk_prot, - &tls_prots[ip_ver][ctx->tx_conf][ctx->rx_conf]); + &prot->prots[ctx->tx_conf][ctx->rx_conf]); WRITE_ONCE(sk->sk_socket->ops, - &tls_proto_ops[ip_ver][ctx->tx_conf][ctx->rx_conf]); + &prot->proto_ops[ctx->tx_conf][ctx->rx_conf]); } int wait_on_pending_writer(struct sock *sk, long *timeo) @@ -XXX,XX +XXX,XX @@ static void tls_write_space(struct sock *sk) ctx->sk_write_space(sk); } +static void tls_prot_put(struct tls_prot *prot) +{ + if (refcount_dec_and_test(&prot->refcnt)) { + spin_lock_bh(&tls_prot_lock); + list_del_rcu(&prot->list); + spin_unlock_bh(&tls_prot_lock); + call_rcu(&prot->rcu, tls_prot_free); + } +} + /** * tls_ctx_free() - free TLS ULP context * @sk: socket to with @ctx is attached @@ -XXX,XX +XXX,XX @@ void tls_ctx_free(struct sock *sk, struct tls_context *ctx) if (!ctx) return; + if (ctx->prot) { + tls_prot_put(ctx->prot); + ctx->prot = NULL; + } + memzero_explicit(&ctx->crypto_send, sizeof(ctx->crypto_send)); memzero_explicit(&ctx->crypto_recv, sizeof(ctx->crypto_recv)); mutex_destroy(&ctx->tx_lock); @@ -XXX,XX +XXX,XX @@ static int tls_disconnect(struct sock *sk, int flags) return -EOPNOTSUPP; } -struct tls_context *tls_ctx_create(struct sock *sk) +struct tls_context *tls_ctx_create(struct sock *sk, struct tls_prot *prot) { struct inet_connection_sock *icsk = inet_csk(sk); struct tls_context *ctx; @@ -XXX,XX +XXX,XX @@ struct tls_context *tls_ctx_create(struct sock *sk) mutex_init(&ctx->tx_lock); ctx->sk_proto = READ_ONCE(sk->sk_prot); + ctx->prot = prot; ctx->sk = sk; /* Release semantic of rcu_assign_pointer() ensures that * ctx->sk_proto is visible before changing sk->sk_prot in @@ -XXX,XX +XXX,XX @@ static void build_proto_ops(struct proto_ops ops[TLS_NUM_CONFIG][TLS_NUM_CONFIG] #endif } -static void tls_build_proto(struct sock *sk) +static struct tls_prot *tls_build_proto(struct sock *sk) { int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4; struct proto *prot = READ_ONCE(sk->sk_prot); + struct tls_prot *proto, *cache; - /* Build IPv6 TLS whenever the address of tcpv6 _prot changes */ - if (ip_ver == TLSV6 && - unlikely(prot != smp_load_acquire(&saved_tcpv6_prot))) { - mutex_lock(&tcpv6_prot_mutex); - if (likely(prot != saved_tcpv6_prot)) { - build_protos(tls_prots[TLSV6], prot); - build_proto_ops(tls_proto_ops[TLSV6], - sk->sk_socket->ops); - smp_store_release(&saved_tcpv6_prot, prot); - } - mutex_unlock(&tcpv6_prot_mutex); - } + if (!sk->sk_socket) + return NULL; - if (ip_ver == TLSV4 && - unlikely(prot != smp_load_acquire(&saved_tcpv4_prot))) { - mutex_lock(&tcpv4_prot_mutex); - if (likely(prot != saved_tcpv4_prot)) { - build_protos(tls_prots[TLSV4], prot); - build_proto_ops(tls_proto_ops[TLSV4], - sk->sk_socket->ops); - smp_store_release(&saved_tcpv4_prot, prot); - } - mutex_unlock(&tcpv4_prot_mutex); + cache = tls_prot_find(prot, ip_ver); + if (cache) + return cache; + + proto = kzalloc_obj(*proto, GFP_KERNEL); + if (!proto) + return NULL; + + spin_lock_bh(&tls_prot_lock); + cache = tls_prot_find(prot, ip_ver); + if (cache) { + spin_unlock_bh(&tls_prot_lock); + kfree(proto); + return cache; } + + proto->ip_ver = ip_ver; + proto->prot = prot; + refcount_set(&proto->refcnt, 1); + build_protos(proto->prots, prot); + build_proto_ops(proto->proto_ops, + sk->sk_socket->ops); + list_add_rcu(&proto->list, &tls_prot_list); + spin_unlock_bh(&tls_prot_lock); + + return proto; } static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], @@ -XXX,XX +XXX,XX @@ static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], static int tls_init(struct sock *sk) { struct tls_context *ctx; + struct tls_prot *prot; int rc = 0; - tls_build_proto(sk); + prot = tls_build_proto(sk); + if (!prot) + return -ENOMEM; #ifdef CONFIG_TLS_TOE - if (tls_toe_bypass(sk)) + if (tls_toe_bypass(sk, prot)) return 0; #endif @@ -XXX,XX +XXX,XX @@ static int tls_init(struct sock *sk) * to modify the accept implementation to clone rather then * share the ulp context. */ - if (sk->sk_state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) { + tls_prot_put(prot); return -ENOTCONN; + } /* allocate tls context */ write_lock_bh(&sk->sk_callback_lock); - ctx = tls_ctx_create(sk); + ctx = tls_ctx_create(sk, prot); if (!ctx) { + tls_prot_put(prot); rc = -ENOMEM; goto out; } @@ -XXX,XX +XXX,XX @@ static int __init tls_register(void) static void __exit tls_unregister(void) { tcp_unregister_ulp(&tcp_tls_ulp_ops); + tls_prot_cleanup(); tls_strp_dev_exit(); tls_device_cleanup(); unregister_pernet_subsys(&tls_proc_ops); diff --git a/net/tls/tls_toe.c b/net/tls/tls_toe.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_toe.c +++ b/net/tls/tls_toe.c @@ -XXX,XX +XXX,XX @@ static void tls_toe_sk_destruct(struct sock *sk) tls_ctx_free(sk, ctx); } -int tls_toe_bypass(struct sock *sk) +int tls_toe_bypass(struct sock *sk, struct tls_prot *prot) { struct tls_toe_device *dev; struct tls_context *ctx; @@ -XXX,XX +XXX,XX @@ int tls_toe_bypass(struct sock *sk) spin_lock_bh(&device_spinlock); list_for_each_entry(dev, &device_list, dev_list) { if (dev->feature && dev->feature(dev)) { - ctx = tls_ctx_create(sk); + ctx = tls_ctx_create(sk, prot); if (!ctx) goto out; -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> To extend MPTCP support based on TCP TLS, a tls_prot_ops structure has been introduced for TLS, encapsulating TCP-specific helpers within this structure. Add registering, validating and finding functions for this structure to add, validate and find a tls_prot_ops on the global list tls_prot_ops_list. Register TCP-specific structure tls_tcp_ops in tls_register(). Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- include/net/tls.h | 15 +++++++ net/tls/tls_main.c | 100 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 1 deletion(-) diff --git a/include/net/tls.h b/include/net/tls.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -XXX,XX +XXX,XX @@ struct tls_prot_info { u16 tail_size; }; +struct tls_prot_ops { + struct module *owner; + int protocol; + struct list_head list; + + struct sk_buff *(*recv_skb)(struct sock *sk, u32 *off); + bool (*lock_is_held)(struct sock *sk); + void (*read_done)(struct sock *sk, size_t len); + u32 (*get_skb_seq)(struct sk_buff *skb); + int (*skb_get_header)(const struct sk_buff *skb, int offset, + void *to, int len); + bool (*epollin_ready)(const struct sock *sk); + void (*check_app_limited)(struct sock *sk); +}; + struct tls_prot { struct rcu_head rcu; refcount_t refcnt; diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -XXX,XX +XXX,XX @@ CHECK_CIPHER_DESC(TLS_CIPHER_ARIA_GCM_128, tls12_crypto_info_aria_gcm_128); CHECK_CIPHER_DESC(TLS_CIPHER_ARIA_GCM_256, tls12_crypto_info_aria_gcm_256); static LIST_HEAD(tls_prot_list); +static LIST_HEAD(tls_prot_ops_list); static DEFINE_SPINLOCK(tls_prot_lock); static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], const struct proto *base); @@ -XXX,XX +XXX,XX @@ static void tls_prot_cleanup(void) rcu_barrier(); } +static struct tls_prot_ops *tls_prot_ops_find(int protocol) +{ + struct tls_prot_ops *ops, *ret = NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(ops, &tls_prot_ops_list, list) { + if (ops->protocol == protocol) { + ret = ops; + break; + } + } + rcu_read_unlock(); + + return ret; +} + void update_sk_prot(struct sock *sk, struct tls_context *ctx) { struct tls_prot *prot = ctx->prot; @@ -XXX,XX +XXX,XX @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = { .get_info_size = tls_get_info_size, }; +static int tls_validate_prot_ops(const struct tls_prot_ops *ops) +{ + if (!ops->recv_skb || !ops->lock_is_held || + !ops->read_done || !ops->get_skb_seq || + !ops->skb_get_header || !ops->epollin_ready || + !ops->check_app_limited) { + pr_err("%d does not implement required ops\n", ops->protocol); + return -EINVAL; + } + + return 0; +} + +static int tls_register_prot_ops(struct tls_prot_ops *ops) +{ + int ret; + + ret = tls_validate_prot_ops(ops); + if (ret) + return ret; + + spin_lock_bh(&tls_prot_lock); + if (tls_prot_ops_find(ops->protocol)) { + spin_unlock_bh(&tls_prot_lock); + return -EEXIST; + } + + list_add_tail_rcu(&ops->list, &tls_prot_ops_list); + spin_unlock_bh(&tls_prot_lock); + + pr_debug("tls_prot_ops %d registered\n", ops->protocol); + return 0; +} + +static void tls_unregister_prot_ops(struct tls_prot_ops *ops) +{ + spin_lock_bh(&tls_prot_lock); + list_del_rcu(&ops->list); + spin_unlock_bh(&tls_prot_lock); + synchronize_rcu(); +} + +static struct sk_buff *tls_tcp_recv_skb(struct sock *sk, u32 *off) +{ + return tcp_recv_skb(sk, tcp_sk(sk)->copied_seq, off); +} + +static bool tls_tcp_lock_is_held(struct sock *sk) +{ + return sock_owned_by_user_nocheck(sk); +} + +static u32 tls_tcp_get_skb_seq(struct sk_buff *skb) +{ + return TCP_SKB_CB(skb)->seq; +} + +static bool tls_tcp_epollin_ready(const struct sock *sk) +{ + return tcp_epollin_ready(sk, INT_MAX); +} + +static struct tls_prot_ops tls_tcp_ops = { + .owner = THIS_MODULE, + .protocol = IPPROTO_TCP, + .recv_skb = tls_tcp_recv_skb, + .lock_is_held = tls_tcp_lock_is_held, + .read_done = tcp_read_done, + .get_skb_seq = tls_tcp_get_skb_seq, + .skb_get_header = skb_copy_bits, + .epollin_ready = tls_tcp_epollin_ready, + .check_app_limited = tcp_rate_check_app_limited, +}; + static int __init tls_register(void) { int err; @@ -XXX,XX +XXX,XX @@ static int __init tls_register(void) if (err) goto err_pernet; - err = tls_device_init(); + err = tls_register_prot_ops(&tls_tcp_ops); if (err) goto err_strp; + err = tls_device_init(); + if (err) + goto err_ops; + tcp_register_ulp(&tcp_tls_ulp_ops); return 0; +err_ops: + tls_unregister_prot_ops(&tls_tcp_ops); err_strp: tls_strp_dev_exit(); err_pernet: @@ -XXX,XX +XXX,XX @@ static int __init tls_register(void) static void __exit tls_unregister(void) { tcp_unregister_ulp(&tcp_tls_ulp_ops); + tls_unregister_prot_ops(&tls_tcp_ops); tls_prot_cleanup(); tls_strp_dev_exit(); tls_device_cleanup(); -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> A pointer to struct tls_prot_ops, named 'ops', has been added to struct tls_prot. The places originally calling TLS-specific helpers have now been modified to indirectly invoke them via 'ops' pointer in tls_prot. In tls_build_proto(), prot->ops is assigned either 'tls_mptcp_ops' or 'tls_tcp_ops' based on the socket protocol. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- include/net/tls.h | 1 + net/tls/tls_main.c | 13 ++++++++++++- net/tls/tls_strp.c | 26 ++++++++++++++++++-------- net/tls/tls_sw.c | 5 +++-- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -XXX,XX +XXX,XX @@ struct tls_prot { struct list_head list; int ip_ver; const struct proto *prot; + const struct tls_prot_ops *ops; struct proto prots[TLS_NUM_CONFIG][TLS_NUM_CONFIG]; struct proto_ops proto_ops[TLS_NUM_CONFIG][TLS_NUM_CONFIG]; }; diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -XXX,XX +XXX,XX @@ static void tls_prot_cleanup(void) spin_lock_bh(&tls_prot_lock); list_for_each_entry_safe(prot, tmp, &tls_prot_list, list) { list_del_rcu(&prot->list); + module_put(prot->ops->owner); call_rcu(&prot->rcu, tls_prot_free); } spin_unlock_bh(&tls_prot_lock); @@ -XXX,XX +XXX,XX @@ int tls_push_sg(struct sock *sk, ctx->splicing_pages = true; while (1) { /* is sending application-limited? */ - tcp_rate_check_app_limited(sk); + ctx->prot->ops->check_app_limited(sk); p = sg_page(sg); retry: bvec_set_page(&bvec, p, size, offset); @@ -XXX,XX +XXX,XX @@ static void tls_prot_put(struct tls_prot *prot) spin_lock_bh(&tls_prot_lock); list_del_rcu(&prot->list); spin_unlock_bh(&tls_prot_lock); + module_put(prot->ops->owner); call_rcu(&prot->rcu, tls_prot_free); } } @@ -XXX,XX +XXX,XX @@ static struct tls_prot *tls_build_proto(struct sock *sk) int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4; struct proto *prot = READ_ONCE(sk->sk_prot); struct tls_prot *proto, *cache; + struct tls_prot_ops *ops; if (!sk->sk_socket) return NULL; @@ -XXX,XX +XXX,XX @@ static struct tls_prot *tls_build_proto(struct sock *sk) return cache; } + ops = tls_prot_ops_find(sk->sk_protocol); + if (!ops || !try_module_get(ops->owner)) { + spin_unlock_bh(&tls_prot_lock); + kfree(proto); + return NULL; + } + proto->ip_ver = ip_ver; proto->prot = prot; + proto->ops = ops; refcount_set(&proto->refcnt, 1); build_protos(proto->prots, prot); build_proto_ops(proto->proto_ops, diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_strp.c +++ b/net/tls/tls_strp.c @@ -XXX,XX +XXX,XX @@ struct sk_buff *tls_strp_msg_detach(struct tls_sw_context_rx *ctx) int tls_strp_msg_cow(struct tls_sw_context_rx *ctx) { struct tls_strparser *strp = &ctx->strp; + struct tls_context *tls_ctx = tls_get_ctx(strp->sk); struct sk_buff *skb; if (strp->copy_mode) @@ -XXX,XX +XXX,XX @@ int tls_strp_msg_cow(struct tls_sw_context_rx *ctx) tls_strp_anchor_free(strp); strp->anchor = skb; - tcp_read_done(strp->sk, strp->stm.full_len); + tls_ctx->prot->ops->read_done(strp->sk, strp->stm.full_len); strp->copy_mode = 1; return 0; @@ -XXX,XX +XXX,XX @@ static int tls_strp_read_copyin(struct tls_strparser *strp) static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort) { + struct tls_context *ctx = tls_get_ctx(strp->sk); struct skb_shared_info *shinfo; struct page *page; int need_spc, len; @@ -XXX,XX +XXX,XX @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort) * to read the data out. Otherwise the connection will stall. * Without pressure threshold of INT_MAX will never be ready. */ - if (likely(qshort && !tcp_epollin_ready(strp->sk, INT_MAX))) + if (likely(qshort && !ctx->prot->ops->epollin_ready(strp->sk))) return 0; shinfo = skb_shinfo(strp->anchor); @@ -XXX,XX +XXX,XX @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort) static bool tls_strp_check_queue_ok(struct tls_strparser *strp) { unsigned int len = strp->stm.offset + strp->stm.full_len; + struct tls_context *ctx = tls_get_ctx(strp->sk); struct sk_buff *first, *skb; u32 seq; first = skb_shinfo(strp->anchor)->frag_list; skb = first; - seq = TCP_SKB_CB(first)->seq; + seq = ctx->prot->ops->get_skb_seq(first); /* Make sure there's no duplicate data in the queue, * and the decrypted status matches. @@ -XXX,XX +XXX,XX @@ static bool tls_strp_check_queue_ok(struct tls_strparser *strp) len -= skb->len; skb = skb->next; - if (TCP_SKB_CB(skb)->seq != seq) + if (ctx->prot->ops->get_skb_seq(skb) != seq) return false; if (skb_cmp_decrypted(first, skb)) return false; @@ -XXX,XX +XXX,XX @@ static bool tls_strp_check_queue_ok(struct tls_strparser *strp) static void tls_strp_load_anchor_with_queue(struct tls_strparser *strp, int len) { - struct tcp_sock *tp = tcp_sk(strp->sk); + struct tls_context *ctx = tls_get_ctx(strp->sk); struct sk_buff *first; u32 offset; - first = tcp_recv_skb(strp->sk, tp->copied_seq, &offset); + first = ctx->prot->ops->recv_skb(strp->sk, &offset); if (WARN_ON_ONCE(!first)) return; @@ -XXX,XX +XXX,XX @@ void tls_strp_check_rcv(struct tls_strparser *strp) /* Lower sock lock held */ void tls_strp_data_ready(struct tls_strparser *strp) { + struct tls_context *ctx = tls_get_ctx(strp->sk); + + if (!ctx) + return; + /* This check is needed to synchronize with do_tls_strp_work. * do_tls_strp_work acquires a process lock (lock_sock) whereas * the lock held here is bh_lock_sock. The two locks can be @@ -XXX,XX +XXX,XX @@ void tls_strp_data_ready(struct tls_strparser *strp) * allows a thread in BH context to safely check if the process * lock is held. In this case, if the lock is held, queue work. */ - if (sock_owned_by_user_nocheck(strp->sk)) { + if (ctx->prot->ops->lock_is_held(strp->sk)) { queue_work(tls_strp_wq, &strp->work); return; } @@ -XXX,XX +XXX,XX @@ static void tls_strp_work(struct work_struct *w) void tls_strp_msg_done(struct tls_strparser *strp) { + struct tls_context *ctx = tls_get_ctx(strp->sk); + WARN_ON(!strp->stm.full_len); if (likely(!strp->copy_mode)) - tcp_read_done(strp->sk, strp->stm.full_len); + ctx->prot->ops->read_done(strp->sk, strp->stm.full_len); else tls_strp_flush_anchor_copy(strp); diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -XXX,XX +XXX,XX @@ bool tls_sw_sock_is_readable(struct sock *sk) int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb) { struct tls_context *tls_ctx = tls_get_ctx(strp->sk); + const struct tls_prot_ops *ops = tls_ctx->prot->ops; struct tls_prot_info *prot = &tls_ctx->prot_info; char header[TLS_HEADER_SIZE + TLS_MAX_IV_SIZE]; size_t cipher_overhead; @@ -XXX,XX +XXX,XX @@ int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb) } /* Linearize header to local buffer */ - ret = skb_copy_bits(skb, strp->stm.offset, header, prot->prepend_size); + ret = ops->skb_get_header(skb, strp->stm.offset, header, prot->prepend_size); if (ret < 0) goto read_failure; @@ -XXX,XX +XXX,XX @@ int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb) } tls_device_rx_resync_new_rec(strp->sk, data_len + TLS_HEADER_SIZE, - TCP_SKB_CB(skb)->seq + strp->stm.offset); + ops->get_skb_seq(skb) + strp->stm.offset); return data_len + TLS_HEADER_SIZE; read_failure: -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> This patch implements the MPTCP-specific struct tls_prot_ops, named 'tls_mptcp_ops'. Passing an MPTCP socket to tcp_sock_rate_check_app_limited() can trigger a crash. Here, an MPTCP version of check_app_limited() is implemented, which calls tcp_sock_rate_check_app_limited() for each subflow. When MPTCP implements lock_is_held interface, it not only checks sock_owned_by_user_nocheck(sk) as TCP does, but also needs to check whether the MPTCP data lock is held. This is required because TLS may call lock_is_held from softirq context with bh_lock_sock held. Checking both conditions ensures TLS always defers to workqueue when the MPTCP data lock is held, avoiding deadlock. Implement mptcp_skb_get_header() to handle fragmented MPTCP skbs when copying TLS record headers. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- include/net/mptcp.h | 2 + include/net/tcp.h | 1 + net/ipv4/tcp.c | 9 +++- net/mptcp/protocol.c | 113 +++++++++++++++++++++++++++++++++++++++++++ net/mptcp/protocol.h | 1 + net/tls/tls_main.c | 13 +++++ 6 files changed, 137 insertions(+), 2 deletions(-) diff --git a/include/net/mptcp.h b/include/net/mptcp.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -XXX,XX +XXX,XX @@ struct mptcp_pm_ops { void (*release)(struct mptcp_sock *msk); } ____cacheline_aligned_in_smp; +extern struct tls_prot_ops tls_mptcp_ops; + #ifdef CONFIG_MPTCP void mptcp_init(void); diff --git a/include/net/tcp.h b/include/net/tcp.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -XXX,XX +XXX,XX @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize) /* tcp.c */ void tcp_get_info(struct sock *, struct tcp_info *); +void tcp_sock_rate_check_app_limited(struct tcp_sock *tp); void tcp_rate_check_app_limited(struct sock *sk); /* Read 'sendfile()'-style from a TCP socket */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index XXXXXXX..XXXXXXX 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -XXX,XX +XXX,XX @@ int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *copied, } /* If a gap is detected between sends, mark the socket application-limited. */ -void tcp_rate_check_app_limited(struct sock *sk) +void tcp_sock_rate_check_app_limited(struct tcp_sock *tp) { - struct tcp_sock *tp = tcp_sk(sk); + struct sock *sk = (struct sock *)tp; if (/* We have less than one packet to send. */ tp->write_seq - tp->snd_nxt < tp->mss_cache && @@ -XXX,XX +XXX,XX @@ void tcp_rate_check_app_limited(struct sock *sk) tp->app_limited = (tp->delivered + tcp_packets_in_flight(tp)) ? : 1; } + +void tcp_rate_check_app_limited(struct sock *sk) +{ + tcp_sock_rate_check_app_limited(tcp_sk(sk)); +} EXPORT_SYMBOL_GPL(tcp_rate_check_app_limited); int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -XXX,XX +XXX,XX @@ #include <net/mptcp.h> #include <net/hotdata.h> #include <net/xfrm.h> +#include <net/tls.h> #include <asm/ioctls.h> #include "protocol.h" #include "mib.h" @@ -XXX,XX +XXX,XX @@ int __init mptcp_proto_v6_init(void) return err; } #endif + +static bool mptcp_lock_is_held(struct sock *sk) +{ + return sock_owned_by_user_nocheck(sk) || + mptcp_data_is_locked(sk); +} + +static void mptcp_read_done(struct sock *sk, size_t len) +{ + struct mptcp_sock *msk = mptcp_sk(sk); + struct sk_buff *skb; + size_t left; + u32 offset; + + msk_owned_by_me(msk); + + if (sk->sk_state == TCP_LISTEN) + return; + + left = len; + while (left && (skb = mptcp_recv_skb(sk, &offset)) != NULL) { + int used; + + used = min_t(size_t, skb->len - offset, left); + msk->bytes_consumed += used; + MPTCP_SKB_CB(skb)->offset += used; + MPTCP_SKB_CB(skb)->map_seq += used; + left -= used; + + if (skb->len > offset + used) + break; + + mptcp_eat_recv_skb(sk, skb); + } + + mptcp_rcv_space_adjust(msk, len - left); + + /* Clean up data we have read: This will do ACK frames. */ + if (left != len) + mptcp_cleanup_rbuf(msk, len - left); +} + +static u32 mptcp_get_skb_seq(struct sk_buff *skb) +{ + return MPTCP_SKB_CB(skb)->map_seq - MPTCP_SKB_CB(skb)->offset; +} + +static int mptcp_skb_get_header(const struct sk_buff *skb, int off, + void *buf, int len) +{ + const struct sk_buff *iter = skb_shinfo(skb)->frag_list; + int copied = 0; + int ret = 0; + + if (!iter) + return skb_copy_bits(skb, off, buf, len); + + /* Make absolute to positive */ + off -= MPTCP_SKB_CB(iter)->offset; + + while (iter && copied < len) { + int skb_off = MPTCP_SKB_CB(iter)->offset; + int data_len = iter->len - skb_off; + int count; + + if (off >= data_len) { + off -= data_len; /* MPTCP skb avail data */ + iter = iter->next; + continue; + } + + count = min((int)(data_len - off), len - copied); + ret = skb_copy_bits(iter, skb_off + off, buf + copied, count); + if (ret) + break; + copied += count; + off = 0; + iter = iter->next; + } + + if (copied < len && !ret) + ret = -EFAULT; + return ret; +} + +static void mptcp_check_app_limited(struct sock *sk) +{ + struct mptcp_sock *msk = mptcp_sk(sk); + struct mptcp_subflow_context *subflow; + + mptcp_for_each_subflow(msk, subflow) { + struct sock *ssk = mptcp_subflow_tcp_sock(subflow); + bool slow; + + slow = lock_sock_fast(ssk); + tcp_sock_rate_check_app_limited(tcp_sk(ssk)); + unlock_sock_fast(ssk, slow); + } +} + +struct tls_prot_ops tls_mptcp_ops = { + .owner = THIS_MODULE, + .protocol = IPPROTO_MPTCP, + .recv_skb = mptcp_recv_skb, + .lock_is_held = mptcp_lock_is_held, + .read_done = mptcp_read_done, + .get_skb_seq = mptcp_get_skb_seq, + .skb_get_header = mptcp_skb_get_header, + .epollin_ready = mptcp_epollin_ready, + .check_app_limited = mptcp_check_app_limited, +}; +EXPORT_SYMBOL(tls_mptcp_ops); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ struct mptcp_sock { #define mptcp_data_lock(sk) spin_lock_bh(&(sk)->sk_lock.slock) #define mptcp_data_unlock(sk) spin_unlock_bh(&(sk)->sk_lock.slock) +#define mptcp_data_is_locked(sk) spin_is_locked(&(sk)->sk_lock.slock) #define mptcp_for_each_subflow(__msk, __subflow) \ list_for_each_entry(__subflow, &((__msk)->conn_list), node) diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -XXX,XX +XXX,XX @@ static int __init tls_register(void) if (err) goto err_strp; +#ifdef CONFIG_MPTCP + err = tls_register_prot_ops(&tls_mptcp_ops); + if (err) + goto err_tcp; +#endif + err = tls_device_init(); if (err) goto err_ops; @@ -XXX,XX +XXX,XX @@ static int __init tls_register(void) return 0; err_ops: +#ifdef CONFIG_MPTCP + tls_unregister_prot_ops(&tls_mptcp_ops); +err_tcp: +#endif tls_unregister_prot_ops(&tls_tcp_ops); err_strp: tls_strp_dev_exit(); @@ -XXX,XX +XXX,XX @@ static int __init tls_register(void) static void __exit tls_unregister(void) { tcp_unregister_ulp(&tcp_tls_ulp_ops); +#ifdef CONFIG_MPTCP + tls_unregister_prot_ops(&tls_mptcp_ops); +#endif tls_unregister_prot_ops(&tls_tcp_ops); tls_prot_cleanup(); tls_strp_dev_exit(); -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> MPTCP TLS hardware offload is not yet implemented. Return -EOPNOTSUPP when attempting to enable device offload on MPTCP sockets. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- net/tls/tls_device.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index XXXXXXX..XXXXXXX 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -XXX,XX +XXX,XX @@ int tls_set_device_offload(struct sock *sk) ctx = tls_get_ctx(sk); prot = &ctx->prot_info; + if (sk->sk_protocol == IPPROTO_MPTCP) + return -EOPNOTSUPP; + if (ctx->priv_ctx_tx) return -EEXIST; @@ -XXX,XX +XXX,XX @@ int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx) struct net_device *netdev; int rc = 0; + if (sk->sk_protocol == IPPROTO_MPTCP) + return -EOPNOTSUPP; + if (ctx->crypto_recv.info.version != TLS_1_2_VERSION) return -EOPNOTSUPP; -- 2.43.0
From: Gang Yan <yangang@kylinos.cn> This patch makes mptcp_check_readable() aligned with TCP, and renames it to mptcp_stream_is_readable(). It will be used in the case of KTLS, because 'prot' will be modified, tls_sw_sock_is_readable() is expected to be called from prot->sock_is_readable(). Co-developed-by: Geliang Tang <geliang@kernel.org> Signed-off-by: Geliang Tang <geliang@kernel.org> Signed-off-by: Gang Yan <yangang@kylinos.cn> --- net/mptcp/protocol.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -XXX,XX +XXX,XX @@ void __mptcp_unaccepted_force_close(struct sock *sk) __mptcp_destroy_sock(sk); } -static __poll_t mptcp_check_readable(struct sock *sk) +static bool mptcp_stream_is_readable(struct sock *sk) { - return mptcp_epollin_ready(sk) ? EPOLLIN | EPOLLRDNORM : 0; + if (mptcp_epollin_ready(sk)) + return true; + return sk_is_readable(sk); } static void mptcp_check_listen_stop(struct sock *sk) @@ -XXX,XX +XXX,XX @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock, mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP; if (state != TCP_SYN_SENT && state != TCP_SYN_RECV) { - mask |= mptcp_check_readable(sk); + if (mptcp_stream_is_readable(sk)) + mask |= EPOLLIN | EPOLLRDNORM; if (shutdown & SEND_SHUTDOWN) mask |= EPOLLOUT | EPOLLWRNORM; else -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> Add mptcp_getsockopt_tcp_ulp() to handle TCP_ULP getsockopt on MPTCP sockets. The helper reads the user length once, checks for negative value, takes the socket lock, caps the length to TCP_ULP_NAME_MAX, and copies the ULP name (or sets the length to zero if no ULP is attached) to userspace. The lock ensures safe access to icsk->icsk_ulp_ops. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- net/mptcp/sockopt.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -XXX,XX +XXX,XX @@ static int mptcp_put_int_option(struct mptcp_sock *msk, char __user *optval, return 0; } +static int mptcp_getsockopt_tcp_ulp(struct sock *sk, + char __user *optval, + int __user *optlen) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + int ret = 0, len; + + if (copy_from_sockptr(&len, USER_SOCKPTR(optlen), sizeof(int))) + return -EFAULT; + + if (len < 0) + return -EINVAL; + + lock_sock(sk); + len = min_t(unsigned int, len, TCP_ULP_NAME_MAX); + if (!icsk->icsk_ulp_ops) { + len = 0; + if (copy_to_sockptr(USER_SOCKPTR(optlen), &len, sizeof(int))) + ret = -EFAULT; + goto out; + } + if (copy_to_sockptr(USER_SOCKPTR(optlen), &len, sizeof(int))) { + ret = -EFAULT; + goto out; + } + if (copy_to_sockptr(USER_SOCKPTR(optval), icsk->icsk_ulp_ops->name, + len)) + ret = -EFAULT; +out: + release_sock(sk); + return ret; +} + static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname, char __user *optval, int __user *optlen) { @@ -XXX,XX +XXX,XX @@ static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname, switch (optname) { case TCP_ULP: + return mptcp_getsockopt_tcp_ulp(sk, optval, optlen); case TCP_CONGESTION: case TCP_INFO: case TCP_CC_INFO: -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> Allow MPTCP sockets to set the TCP_ULP socket option to enable TLS. Add mptcp_setsockopt_tcp_ulp() which validates the socket state (must not be CLOSE or LISTEN), only accepts "tls" as the ULP name, and then calls tcp_set_ulp(). Include TCP_ULP in the list of supported options in supported_sockopt(), and handle it in setsockopt_sol_tcp() instead of returning -EOPNOTSUPP. Call tcp_cleanup_ulp() in mptcp_destroy_common() to release ULP module's reference count. On a fallback MPTCP socket, the ULP is already set to "mptcp". Setting "tls" will fail with -EEXIST, so no special handling is needed. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- net/mptcp/protocol.c | 1 + net/mptcp/sockopt.c | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -XXX,XX +XXX,XX @@ static void mptcp_destroy(struct sock *sk) /* allow the following to close even the initial subflow */ msk->free_first = 1; mptcp_destroy_common(msk); + tcp_cleanup_ulp(sk); sk_sockets_allocated_dec(sk); } diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -XXX,XX +XXX,XX @@ static bool mptcp_supported_sockopt(int level, int optname) case TCP_FASTOPEN_CONNECT: case TCP_FASTOPEN_KEY: case TCP_FASTOPEN_NO_COOKIE: + case TCP_ULP: return true; } @@ -XXX,XX +XXX,XX @@ static int mptcp_setsockopt_all_sf(struct mptcp_sock *msk, int level, return ret; } +static int mptcp_setsockopt_tcp_ulp(struct sock *sk, sockptr_t optval, + unsigned int optlen) +{ + char name[TCP_ULP_NAME_MAX]; + int err = 0; + size_t len; + int val; + + if (optlen < 1) + return -EINVAL; + + len = min_t(long, TCP_ULP_NAME_MAX - 1, optlen); + val = strncpy_from_sockptr(name, optval, len); + if (val < 0) + return -EFAULT; + name[val] = 0; + + if (strcmp(name, "tls")) + return -EOPNOTSUPP; + + sockopt_lock_sock(sk); + if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) { + err = -ENOTCONN; + goto out; + } + err = tcp_set_ulp(sk, name); +out: + sockopt_release_sock(sk); + return err; +} + static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname, sockptr_t optval, unsigned int optlen) { @@ -XXX,XX +XXX,XX @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname, switch (optname) { case TCP_ULP: - return -EOPNOTSUPP; + return mptcp_setsockopt_tcp_ulp(sk, optval, optlen); case TCP_CONGESTION: return mptcp_setsockopt_sol_tcp_congestion(msk, optval, optlen); case TCP_DEFER_ACCEPT: -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> With KTLS being implemented, "tls" should no longer be used in sock_test_tcpulp(), it breaks mptcp_connect.sh tests. Another ULP name, "espintcp", is set instead in this patch. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/mptcp/config | 4 ++++ tools/testing/selftests/net/mptcp/mptcp_connect.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/config b/tools/testing/selftests/net/mptcp/config index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/mptcp/config +++ b/tools/testing/selftests/net/mptcp/config @@ -XXX,XX +XXX,XX @@ CONFIG_NFT_SOCKET=m CONFIG_NFT_TPROXY=m CONFIG_SYN_COOKIES=y CONFIG_VETH=y +CONFIG_INET_ESP=y +CONFIG_INET_ESPINTCP=y +CONFIG_INET6_ESP=y +CONFIG_INET6_ESPINTCP=y diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.c +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c @@ -XXX,XX +XXX,XX @@ static void sock_test_tcpulp(int sock, int proto, unsigned int line) if (buflen > 0) { if (strcmp(buf, "mptcp") != 0) xerror("unexpected ULP '%s' for proto %d at line %u", buf, proto, line); - ret = do_ulp_so(sock, "tls"); + ret = do_ulp_so(sock, "espintcp"); if (ret == 0) X("setsockopt"); } else if (proto == IPPROTO_MPTCP) { - ret = do_ulp_so(sock, "tls"); + ret = do_ulp_so(sock, "espintcp"); if (ret != -1) X("setsockopt"); } -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> To enable easy MPTCP socket creation in MPTCP TLS tests, two protocol parameters (cli_proto and srv_proto) have been added to ulp_sock_pair(). These are passed as third arguments of socket(): 0 creates TCP sockets, IPPROTO_MPTCP creates MPTCP sockets. A new variant "mptcp" is added both in FIXTURE_VARIANT(tls) to control whether to create MPTCP sockets or not for tests. Add is_mptcp_enable() helper to check MPTCP support. Used in FIXTURE_SETUP(tls) to skip MPTCP variants when MPTCP is not enabled. Also accept EOPNOTSUPP when setting TCP_ULP on MPTCP sockets, as they may return this error in addition to ENOENT. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/tls.c | 46 +++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -XXX,XX +XXX,XX @@ #define TLS_PAYLOAD_MAX_LEN 16384 #define SOL_TLS 282 +#ifndef IPPROTO_MPTCP +#define IPPROTO_MPTCP 262 +#endif + static int fips_enabled; struct tls_crypto_info_keys { @@ -XXX,XX +XXX,XX @@ static void memrnd(void *s, size_t n) *byte++ = rand(); } -static void ulp_sock_pair(struct __test_metadata *_metadata, - int *fd, int *cfd, bool *notls) +static void __ulp_sock_pair(struct __test_metadata *_metadata, + int *fd, int *cfd, bool *notls, + int cli_proto, int srv_proto) { struct sockaddr_in addr; socklen_t len; @@ -XXX,XX +XXX,XX @@ static void ulp_sock_pair(struct __test_metadata *_metadata, addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = 0; - *fd = socket(AF_INET, SOCK_STREAM, 0); - sfd = socket(AF_INET, SOCK_STREAM, 0); + *fd = socket(AF_INET, SOCK_STREAM, cli_proto); + sfd = socket(AF_INET, SOCK_STREAM, srv_proto); ret = bind(sfd, &addr, sizeof(addr)); ASSERT_EQ(ret, 0); @@ -XXX,XX +XXX,XX @@ static void ulp_sock_pair(struct __test_metadata *_metadata, ret = setsockopt(*fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")); if (ret != 0) { - ASSERT_EQ(errno, ENOENT); + ASSERT_TRUE(errno == ENOENT || errno == EOPNOTSUPP); *notls = true; printf("Failure setting TCP_ULP, testing without tls\n"); return; @@ -XXX,XX +XXX,XX @@ static void ulp_sock_pair(struct __test_metadata *_metadata, ASSERT_EQ(ret, 0); } +static void ulp_sock_pair(struct __test_metadata *_metadata, + int *fd, int *cfd, bool *notls) +{ + __ulp_sock_pair(_metadata, fd, cfd, notls, 0, 0); +} + /* Produce a basic cmsg */ static int tls_send_cmsg(int fd, unsigned char record_type, void *data, size_t len, int flags) @@ -XXX,XX +XXX,XX @@ FIXTURE_VARIANT(tls) uint16_t tls_version; uint16_t cipher_type; bool nopad, fips_non_compliant; + bool mptcp; }; FIXTURE_VARIANT_ADD(tls, 12_aes_gcm) @@ -XXX,XX +XXX,XX @@ FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_256) .cipher_type = TLS_CIPHER_ARIA_GCM_256, }; +static bool is_mptcp_enable(void) +{ + char buf[16] = { 0 }; + ssize_t n; + int fd; + + fd = open("/proc/sys/net/mptcp/enabled", O_RDONLY); + if (fd < 0) + return false; + + n = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (n <= 0) + return false; + return (atoi(buf) == 1); +} + FIXTURE_SETUP(tls) { struct tls_crypto_info_keys tls12; @@ -XXX,XX +XXX,XX @@ FIXTURE_SETUP(tls) if (fips_enabled && variant->fips_non_compliant) SKIP(return, "Unsupported cipher in FIPS mode"); + if (variant->mptcp && !is_mptcp_enable()) + SKIP(return, "no MPTCP support"); + tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 0); - ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls); + __ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls, + variant->mptcp ? IPPROTO_MPTCP : 0, + variant->mptcp ? IPPROTO_MPTCP : 0); if (self->notls) return; -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> MPTCP requires longer timeouts in pollin test due to subflow establishment delays and slower state transitions. Increase timeout values to prevent false failures: # RUN tls.13_sm4_ccm_mptcp.pollin ... # tls.c:1411:pollin:Expected poll(&fd, 1, 20) (0) == 1 (1) # tls.c:1412:pollin:Expected fd.revents & POLLIN (0) == 1 (1) # pollin: Test failed # FAIL tls.13_sm4_ccm_mptcp.pollin not ok 357 tls.13_sm4_ccm_mptcp.pollin Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/tls.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -XXX,XX +XXX,XX @@ TEST_F(tls, bidir) TEST_F(tls, pollin) { + int timeout = variant->mptcp ? 100 : 20; char const *test_str = "test_poll"; struct pollfd fd = { 0, 0, 0 }; char buf[10]; @@ -XXX,XX +XXX,XX @@ TEST_F(tls, pollin) fd.fd = self->cfd; fd.events = POLLIN; - EXPECT_EQ(poll(&fd, 1, 20), 1); + EXPECT_EQ(poll(&fd, 1, timeout), 1); EXPECT_EQ(fd.revents & POLLIN, 1); EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_WAITALL), send_len); /* Test timing out */ - EXPECT_EQ(poll(&fd, 1, 20), 0); + EXPECT_EQ(poll(&fd, 1, timeout), 0); } TEST_F(tls, poll_wait) -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> Increase the data size in nonblocking tests to accommodate MPTCP's multi-subflow behavior and ensure sufficient data for testing, avoiding the following errors: # RUN tls.12_aria_gcm_mptcp.nonblocking ... # tls.c:1534:nonblocking:Expected 0 (0) != eagain (0) # nonblocking: Test failed Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/tls.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -XXX,XX +XXX,XX @@ TEST_F(tls, nonblocking) int flags; int res; + if (variant->mptcp) + data *= 4; + flags = fcntl(self->fd, F_GETFL, 0); fcntl(self->fd, F_SETFL, flags | O_NONBLOCK); fcntl(self->cfd, F_SETFL, flags | O_NONBLOCK); -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> In the shutdown_reuse test, after shutdown and close, bind() may fail with EINVAL for MPTCP sockets due to asynchronous state transition of the top-level MPTCP socket. Retry bind() on EINVAL for up to 1000 iterations (1 second) to allow the MPTCP socket to complete its state transition. This fixes the following intermittent failures: # RUN tls.12_aes_gcm_mptcp.shutdown_reuse ... # tls.c:1790:shutdown_reuse:Expected ret (-1) == 0 (0) # shutdown_reuse: Test failed # FAIL tls.12_aes_gcm_mptcp.shutdown_reuse not ok 14 tls.12_aes_gcm_mptcp.shutdown_reuse # RUN tls.13_aes_gcm_mptcp.shutdown_reuse ... # tls.c:1790:shutdown_reuse:Expected ret (-1) == 0 (0) # shutdown_reuse: Test failed # FAIL tls.13_aes_gcm_mptcp.shutdown_reuse not ok 15 tls.13_aes_gcm_mptcp.shutdown_reuse # RUN tls.12_chacha_mptcp.shutdown_reuse ... # OK tls.12_chacha_mptcp.shutdown_reuse ok 16 tls.12_chacha_mptcp.shutdown_reuse # RUN tls.13_chacha_mptcp.shutdown_reuse ... # OK tls.13_chacha_mptcp.shutdown_reuse ok 17 tls.13_chacha_mptcp.shutdown_reuse # RUN tls.13_sm4_gcm_mptcp.shutdown_reuse ... # tls.c:1790:shutdown_reuse:Expected ret (-1) == 0 (0) # shutdown_reuse: Test failed # FAIL tls.13_sm4_gcm_mptcp.shutdown_reuse not ok 18 tls.13_sm4_gcm_mptcp.shutdown_reuse This is only done for MPTCP variants to avoid slowing down plain TCP tests. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/tls.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -XXX,XX +XXX,XX @@ TEST_F(tls, shutdown_unsent) TEST_F(tls, shutdown_reuse) { struct sockaddr_in addr; + int i = 0; int ret; shutdown(self->fd, SHUT_RDWR); @@ -XXX,XX +XXX,XX @@ TEST_F(tls, shutdown_reuse) addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = 0; +retry: ret = bind(self->fd, &addr, sizeof(addr)); + if (variant->mptcp && + ret < 0 && errno == EINVAL && i++ < 1000) { + usleep(1000); + goto retry; + } EXPECT_EQ(ret, 0); ret = listen(self->fd, 10); EXPECT_EQ(ret, -1); -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> The multi_chunk_sendfile test can time out with the default 30-second limit when run on certain configurations (e.g., MPTCP). Add a 240-second timeout using TEST_F_TIMEOUT to prevent failure: # multi_chunk_sendfile: Test terminated by timeout 30 # FAIL tls.13_chacha_mptcp.multi_chunk_sendfile not ok 204 tls.13_chacha_mptcp.multi_chunk_sendfile Suggested-by: Paolo Abeni <pabeni@redhat.com> Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -XXX,XX +XXX,XX @@ static void chunked_sendfile(struct __test_metadata *_metadata, close(fd); } -TEST_F(tls, multi_chunk_sendfile) +TEST_F_TIMEOUT(tls, multi_chunk_sendfile, 240) { chunked_sendfile(_metadata, self, 4096, 4096); chunked_sendfile(_metadata, self, 4096, 0); -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> This patch introduces MPTCP test cases for the TLS fixture. These "mptcp" variants are configured to create MPTCP sockets specifically for MPTCP TLS testing purposes. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/tls.c | 96 +++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -XXX,XX +XXX,XX @@ FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_256) .cipher_type = TLS_CIPHER_ARIA_GCM_256, }; +FIXTURE_VARIANT_ADD(tls, 12_aes_gcm_mptcp) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_128, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_aes_gcm_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_128, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 12_chacha_mptcp) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_CHACHA20_POLY1305, + .fips_non_compliant = true, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_chacha_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_CHACHA20_POLY1305, + .fips_non_compliant = true, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_sm4_gcm_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_SM4_GCM, + .fips_non_compliant = true, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_sm4_ccm_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_SM4_CCM, + .fips_non_compliant = true, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 12_aes_ccm_mptcp) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_AES_CCM_128, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_aes_ccm_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_AES_CCM_128, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 12_aes_gcm_256_mptcp) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_256, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_aes_gcm_256_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_256, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 13_nopad_mptcp) +{ + .tls_version = TLS_1_3_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_128, + .nopad = true, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_mptcp) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_ARIA_GCM_128, + .mptcp = true, +}; + +FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_256_mptcp) +{ + .tls_version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_ARIA_GCM_256, + .mptcp = true, +}; + static bool is_mptcp_enable(void) { char buf[16] = { 0 }; -- 2.43.0
From: Geliang Tang <tanggeliang@kylinos.cn> The mptcp tests for tls.c is available now, this patch adds mptcp_tls.sh to test it in the MPTCP CI by default. The script creates a network namespace, sets up the necessary MPTCP endpoints (by default with 4 subflows), and invokes the tls test binary with all MPTCP-specific test variants (e.g., 12_aes_gcm_mptcp, 13_aes_gcm_mptcp, etc.). A symbolic link to the existing tls.c test program is created under the mptcp selftests directory. Additionally, update the kernel config to enable TLS and the required crypto modules (ARIA, CCM, ChaCha20-Poly1305, SM4) so that all test ciphers can be exercised. Co-developed-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Gang Yan <yangang@kylinos.cn> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> --- tools/testing/selftests/net/mptcp/.gitignore | 1 + tools/testing/selftests/net/mptcp/Makefile | 2 + tools/testing/selftests/net/mptcp/config | 5 ++ .../testing/selftests/net/mptcp/mptcp_tls.sh | 61 +++++++++++++++++++ tools/testing/selftests/net/mptcp/tls.c | 1 + 5 files changed, 70 insertions(+) create mode 100755 tools/testing/selftests/net/mptcp/mptcp_tls.sh create mode 120000 tools/testing/selftests/net/mptcp/tls.c diff --git a/tools/testing/selftests/net/mptcp/.gitignore b/tools/testing/selftests/net/mptcp/.gitignore index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/mptcp/.gitignore +++ b/tools/testing/selftests/net/mptcp/.gitignore @@ -XXX,XX +XXX,XX @@ mptcp_diag mptcp_inq mptcp_sockopt pm_nl_ctl +tls *.pcap diff --git a/tools/testing/selftests/net/mptcp/Makefile b/tools/testing/selftests/net/mptcp/Makefile index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/mptcp/Makefile +++ b/tools/testing/selftests/net/mptcp/Makefile @@ -XXX,XX +XXX,XX @@ TEST_PROGS := \ mptcp_connect_splice.sh \ mptcp_join.sh \ mptcp_sockopt.sh \ + mptcp_tls.sh \ pm_netlink.sh \ simult_flows.sh \ userspace_pm.sh \ @@ -XXX,XX +XXX,XX @@ TEST_GEN_FILES := \ mptcp_inq \ mptcp_sockopt \ pm_nl_ctl \ + tls \ # end of TEST_GEN_FILES TEST_FILES := \ diff --git a/tools/testing/selftests/net/mptcp/config b/tools/testing/selftests/net/mptcp/config index XXXXXXX..XXXXXXX 100644 --- a/tools/testing/selftests/net/mptcp/config +++ b/tools/testing/selftests/net/mptcp/config @@ -XXX,XX +XXX,XX @@ CONFIG_INET_ESP=y CONFIG_INET_ESPINTCP=y CONFIG_INET6_ESP=y CONFIG_INET6_ESPINTCP=y +CONFIG_TLS=m +CONFIG_CRYPTO_ARIA=m +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_CHACHA20POLY1305=m +CONFIG_CRYPTO_SM4_GENERIC=m diff --git a/tools/testing/selftests/net/mptcp/mptcp_tls.sh b/tools/testing/selftests/net/mptcp/mptcp_tls.sh new file mode 100755 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/testing/selftests/net/mptcp/mptcp_tls.sh @@ -XXX,XX +XXX,XX @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(dirname "${0}")/mptcp_lib.sh" + +ret=0 +ns1="" +pid="" + +# This function is used in the cleanup trap +#shellcheck disable=SC2317,SC2329 +cleanup() +{ + if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then + kill "$pid" 2>/dev/null + wait "$pid" 2>/dev/null + fi + + mptcp_lib_ns_exit "$ns1" +} + +init() +{ + local max="${1:-4}" + + mptcp_lib_ns_init ns1 + + mptcp_lib_pm_nl_set_limits "$ns1" "$max" "$max" + + local i + for i in $(seq 1 "$max"); do + mptcp_lib_pm_nl_add_endpoint "$ns1" \ + "127.0.0.1" flags signal port 1000"$i" + done +} + +mptcp_lib_check_mptcp + +trap cleanup EXIT + +init + +ip netns exec "$ns1" ./tls -v 12_aes_gcm_mptcp \ + -v 13_aes_gcm_mptcp \ + -v 12_chacha_mptcp \ + -v 13_chacha_mptcp \ + -v 13_sm4_gcm_mptcp \ + -v 13_sm4_ccm_mptcp \ + -v 12_aes_ccm_mptcp \ + -v 13_aes_ccm_mptcp \ + -v 12_aes_gcm_256_mptcp \ + -v 13_aes_gcm_256_mptcp \ + -v 13_nopad_mptcp \ + -v 12_aria_gcm_mptcp \ + -v 12_aria_gcm_256_mptcp & +pid=$! +wait $pid +ret=$? + +mptcp_lib_result_print_all_tap +exit $ret diff --git a/tools/testing/selftests/net/mptcp/tls.c b/tools/testing/selftests/net/mptcp/tls.c new file mode 120000 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/testing/selftests/net/mptcp/tls.c @@ -0,0 +1 @@ +../tls.c \ No newline at end of file -- 2.43.0