diff options
| author | Steven Rostedt <rostedt@goodmis.org> | 2026-09-02 09:55:01 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2026-09-02 11:08:21 -0400 |
| commit | 4617721c502b2ddaa4e324e86da4997edf738fa5 (patch) | |
| tree | 350aa83b47da0b574a814795392b20b0bed83cbc /net/handshake/handshake.h | |
| download | linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.tar.gz linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.zip | |
ftrace: Synchronize the initialization of ftrace_opsgrafted
There's some internal state that ftrace_ops needs to have set, but since
it can be declared outside of the ftrace.c code, it calls
ftrace_ops_init() on the ops in every global function. The issue is that
if two tasks call it on the same ops at the same time it is possible to
have the initialization of one corrupt the initialization of the other
call.
Create a ops_mutex to use to synchronize every initialization of the
ftrace_ops. The mutex is taken within checking the ftrace_ops flag that
states it was initializied but the flag is checked again after the mutex
has been taken. Checking first outside the mutex allows it to shortcut
having to take the mutex. But then the check needs to be done again after
the mute is taken in case of races.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home
Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock")
Reported-by: sashiko-bot@kernel.org
Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'net/handshake/handshake.h')
| -rw-r--r-- | net/handshake/handshake.h | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/net/handshake/handshake.h b/net/handshake/handshake.h new file mode 100644 index 000000000..da61cadd1 --- /dev/null +++ b/net/handshake/handshake.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Generic netlink handshake service + * + * Author: Chuck Lever <chuck.lever@oracle.com> + * + * Copyright (c) 2023, Oracle and/or its affiliates. + */ + +#ifndef _INTERNAL_HANDSHAKE_H +#define _INTERNAL_HANDSHAKE_H + +/* Per-net namespace context */ +struct handshake_net { + spinlock_t hn_lock; /* protects next 3 fields */ + int hn_pending; + int hn_pending_max; + struct list_head hn_requests; + + unsigned long hn_flags; +}; + +enum hn_flags_bits { + HANDSHAKE_F_NET_DRAINING, +}; + +struct file; +struct handshake_proto; + +/* One handshake request */ +struct handshake_req { + struct list_head hr_list; + struct rhash_head hr_rhash; + unsigned long hr_flags; + const struct handshake_proto *hr_proto; + struct file *hr_file; + struct sock *hr_sk; + void (*hr_odestruct)(struct sock *sk); + + /* Always the last field */ + char hr_priv[]; +}; + +enum hr_flags_bits { + HANDSHAKE_F_REQ_COMPLETED, + HANDSHAKE_F_REQ_SESSION, +}; + +struct genl_info; + +/* Invariants for all handshake requests for one transport layer + * security protocol + */ +struct handshake_proto { + int hp_handler_class; + size_t hp_privsize; + unsigned long hp_flags; + + int (*hp_accept)(struct handshake_req *req, + struct genl_info *info, int fd); + void (*hp_done)(struct handshake_req *req, + int status, + struct genl_info *info); + void (*hp_destroy)(struct handshake_req *req); +}; + +enum hp_flags_bits { + HANDSHAKE_F_PROTO_NOTIFY, +}; + +/* alert.c */ +int tls_alert_send(struct socket *sock, u8 level, u8 description); + +/* netlink.c */ +int handshake_genl_notify(struct net *net, const struct handshake_proto *proto, + gfp_t flags); +struct nlmsghdr *handshake_genl_put(struct sk_buff *msg, + struct genl_info *info); +struct handshake_net *handshake_pernet(struct net *net); + +/* request.c */ +struct handshake_req *handshake_req_alloc(const struct handshake_proto *proto, + gfp_t flags); +int handshake_req_hash_init(void); +void handshake_req_hash_destroy(void); +void *handshake_req_private(struct handshake_req *req); +struct handshake_req *handshake_req_hash_lookup(struct sock *sk); +struct handshake_req *handshake_req_next(struct handshake_net *hn, int class); +int handshake_req_submit(struct socket *sock, struct handshake_req *req, + gfp_t flags); +void handshake_complete(struct handshake_req *req, int status, + struct genl_info *info); +bool handshake_req_cancel(struct sock *sk); + +#endif /* _INTERNAL_HANDSHAKE_H */ |
